From 85dfb745ee40232876663ae206cba35f24ab2a40 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 18 Feb 2013 16:24:20 +0100 Subject: af_key: initialize satype in key_notify_policy_flush() This field was left uninitialized. Some user daemons perform check against this field. Signed-off-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- net/key/af_key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/key/af_key.c b/net/key/af_key.c index 9ef79851f297..d5a4a796f025 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2694,6 +2694,7 @@ static int key_notify_policy_flush(const struct km_event *c) hdr->sadb_msg_pid = c->portid; hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_errno = (uint8_t) 0; + hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); return 0; -- cgit v1.2.3 From 75da01e127f7db3b23effa6118336d303e7572a7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 31 Jan 2013 11:25:52 +0000 Subject: ARM: KVM: vgic: force EOIed LRs to the empty state The VGIC doesn't guarantee that an EOIed LR that has been configured to generate a maintenance interrupt will appear as empty. While the code recovers from this situation, it is better to clean the LR and flag it as empty so it can be quickly recycled. Signed-off-by: Marc Zyngier --- arch/arm/kvm/vgic.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c index c9a17316e9fe..76ea1aa5e7d2 100644 --- a/arch/arm/kvm/vgic.c +++ b/arch/arm/kvm/vgic.c @@ -883,8 +883,7 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) lr, irq, vgic_cpu->vgic_lr[lr]); BUG_ON(!test_bit(lr, vgic_cpu->lr_used)); vgic_cpu->vgic_lr[lr] |= GICH_LR_PENDING_BIT; - - goto out; + return true; } /* Try to use another LR for this interrupt */ @@ -898,7 +897,6 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) vgic_cpu->vgic_irq_lr_map[irq] = lr; set_bit(lr, vgic_cpu->lr_used); -out: if (!vgic_irq_is_edge(vcpu, irq)) vgic_cpu->vgic_lr[lr] |= GICH_LR_EOI; @@ -1054,6 +1052,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) } else { vgic_cpu_irq_clear(vcpu, irq); } + + /* + * Despite being EOIed, the LR may not have + * been marked as empty. + */ + set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr); + vgic_cpu->vgic_lr[lr] &= ~GICH_LR_ACTIVE_BIT; } } -- cgit v1.2.3 From 33c83cb3c1d84b76c8270abe5487e77f83a81b22 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 1 Feb 2013 18:28:30 +0000 Subject: ARM: KVM: vgic: take distributor lock on sync_hwstate path Now that the maintenance interrupt handling is actually out of the handler itself, the code becomes quite racy as we can get preempted while we process the state. Wrapping this code around the distributor lock ensures that we're not preempted and relatively race-free. Signed-off-by: Marc Zyngier --- arch/arm/kvm/vgic.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c index 76ea1aa5e7d2..0e4cfe123b38 100644 --- a/arch/arm/kvm/vgic.c +++ b/arch/arm/kvm/vgic.c @@ -1016,21 +1016,6 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) kvm_debug("MISR = %08x\n", vgic_cpu->vgic_misr); - /* - * We do not need to take the distributor lock here, since the only - * action we perform is clearing the irq_active_bit for an EOIed - * level interrupt. There is a potential race with - * the queuing of an interrupt in __kvm_vgic_flush_hwstate(), where we - * check if the interrupt is already active. Two possibilities: - * - * - The queuing is occurring on the same vcpu: cannot happen, - * as we're already in the context of this vcpu, and - * executing the handler - * - The interrupt has been migrated to another vcpu, and we - * ignore this interrupt for this run. Big deal. It is still - * pending though, and will get considered when this vcpu - * exits. - */ if (vgic_cpu->vgic_misr & GICH_MISR_EOI) { /* * Some level interrupts have been EOIed. Clear their @@ -1069,9 +1054,8 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) } /* - * Sync back the VGIC state after a guest run. We do not really touch - * the distributor here (the irq_pending_on_cpu bit is safe to set), - * so there is no need for taking its lock. + * Sync back the VGIC state after a guest run. The distributor lock is + * needed so we don't get preempted in the middle of the state processing. */ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) { @@ -1117,10 +1101,14 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) { + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + if (!irqchip_in_kernel(vcpu->kvm)) return; + spin_lock(&dist->lock); __kvm_vgic_sync_hwstate(vcpu); + spin_unlock(&dist->lock); } int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) -- cgit v1.2.3 From a72d9002f80bffd7e4c7d60e5a9caa0cddffe894 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 28 Feb 2013 10:34:23 +0800 Subject: xen/xen-blkback: preq.dev is used without initialized If call xen_vbd_translate failed, the preq.dev will be not initialized. Use blkif->vbd.pdevice instead (still better to print relative info). Note that before commit 01c681d4c70d64cb72142a2823f27c4146a02e63 (xen/blkback: Don't trust the handle from the frontend.) the value bogus, as it was the guest provided value from req->u.rw.handle rather than the actual device. Signed-off-by: Chen Gang Acked-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index de1f319f7bd7..6d1cc3df2ac6 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -904,7 +904,8 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n", operation == READ ? "read" : "write", preq.sector_number, - preq.sector_number + preq.nr_sects, preq.dev); + preq.sector_number + preq.nr_sects, + blkif->vbd.pdevice); goto fail_response; } -- cgit v1.2.3 From 19b34bdc6d267723f3fc526ae775efba0ca4c39b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:34 +0000 Subject: ASoC: arizona: Move selection of FLL REFCLK into init In preparation for additional features on the FLL this patch moves the code selecting the REFCLK source based on the 32kHz clock into the FLL initialisation function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 28 ++++++++++++++++------------ sound/soc/codecs/arizona.h | 3 +++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ac948a671ea6..c14e7551a332 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1079,7 +1079,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, { struct arizona *arizona = fll->arizona; struct arizona_fll_cfg cfg, sync; - unsigned int reg, val; + unsigned int reg; int syncsrc; bool ena; int ret; @@ -1096,16 +1096,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ena = reg & ARIZONA_FLL1_ENA; if (Fout) { - /* Do we have a 32kHz reference? */ - regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); - switch (val & ARIZONA_CLK_32K_SRC_MASK) { - case ARIZONA_CLK_SRC_MCLK1: - case ARIZONA_CLK_SRC_MCLK2: - syncsrc = val & ARIZONA_CLK_32K_SRC_MASK; - break; - default: - syncsrc = -1; - } + syncsrc = fll->ref_src; if (source == syncsrc) syncsrc = -1; @@ -1115,7 +1106,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ret != 0) return ret; - ret = arizona_calc_fll(fll, &cfg, 32768, Fout); + ret = arizona_calc_fll(fll, &cfg, fll->ref_freq, Fout); if (ret != 0) return ret; } else { @@ -1178,6 +1169,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll) { int ret; + unsigned int val; init_completion(&fll->ok); @@ -1185,6 +1177,18 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->base = base; fll->arizona = arizona; + /* Configure default refclk to 32kHz if we have one */ + regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); + switch (val & ARIZONA_CLK_32K_SRC_MASK) { + case ARIZONA_CLK_SRC_MCLK1: + case ARIZONA_CLK_SRC_MCLK2: + fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK; + break; + default: + fll->ref_src = -1; + } + fll->ref_freq = 32768; + snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id); snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), "FLL%d clock OK", id); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 116372c91f5d..124f9f0ef1ac 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,9 @@ struct arizona_fll { unsigned int fref; unsigned int fout; + int ref_src; + unsigned int ref_freq; + char lock_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN]; }; -- cgit v1.2.3 From 9e359c645fa86daf0e3e5cc2dcbe7388f6e4d16a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:35 +0000 Subject: ASoC: arizona: Tidy up SYNCCLK selection and cache values This patch caches the current SYNCCLK settings in the arizona_fll struct and uses these to simplify the code which determines which source should be used for the REFCLK and SYNCCLK inputs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 101 ++++++++++++++++++++++----------------------- sound/soc/codecs/arizona.h | 2 + 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c14e7551a332..03076efa4d9e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1078,15 +1078,39 @@ int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { struct arizona *arizona = fll->arizona; - struct arizona_fll_cfg cfg, sync; + struct arizona_fll_cfg ref, sync; unsigned int reg; - int syncsrc; bool ena; int ret; if (fll->fref == Fref && fll->fout == Fout) return 0; + if (fll->ref_src < 0 || fll->ref_src == source) { + if (Fout) { + ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (ret != 0) + return ret; + } + + fll->sync_src = -1; + fll->ref_src = source; + fll->ref_freq = Fref; + } else { + if (Fout) { + ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); + if (ret != 0) + return ret; + + ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (ret != 0) + return ret; + } + + fll->sync_src = source; + fll->sync_freq = Fref; + } + ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", @@ -1096,24 +1120,32 @@ int arizona_set_fll(struct arizona_fll *fll, int source, ena = reg & ARIZONA_FLL1_ENA; if (Fout) { - syncsrc = fll->ref_src; + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - if (source == syncsrc) - syncsrc = -1; + arizona_apply_fll(arizona, fll->base, &ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, &sync, + fll->sync_src); - if (syncsrc >= 0) { - ret = arizona_calc_fll(fll, &sync, Fref, Fout); - if (ret != 0) - return ret; + if (!ena) + pm_runtime_get(arizona->dev); - ret = arizona_calc_fll(fll, &cfg, fll->ref_freq, Fout); - if (ret != 0) - return ret; - } else { - ret = arizona_calc_fll(fll, &cfg, Fref, Fout); - if (ret != 0) - return ret; - } + /* Clear any pending completions */ + try_wait_for_completion(&fll->ok); + + regmap_update_bits(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); + if (fll->sync_src >= 0) + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, + ARIZONA_FLL1_SYNC_ENA); + + ret = wait_for_completion_timeout(&fll->ok, + msecs_to_jiffies(250)); + if (ret == 0) + arizona_fll_warn(fll, "Timed out waiting for lock\n"); } else { regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, 0); @@ -1122,42 +1154,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ena) pm_runtime_put_autosuspend(arizona->dev); - - fll->fref = Fref; - fll->fout = Fout; - - return 0; } - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - if (syncsrc >= 0) { - arizona_apply_fll(arizona, fll->base, &cfg, syncsrc); - arizona_apply_fll(arizona, fll->base + 0x10, &sync, source); - } else { - arizona_apply_fll(arizona, fll->base, &cfg, source); - } - - if (!ena) - pm_runtime_get(arizona->dev); - - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (syncsrc >= 0) - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, - ARIZONA_FLL1_SYNC_ENA); - - ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (ret == 0) - arizona_fll_warn(fll, "Timed out waiting for lock\n"); - fll->fref = Fref; fll->fout = Fout; @@ -1176,6 +1174,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->id = id; fll->base = base; fll->arizona = arizona; + fll->sync_src = -1; /* Configure default refclk to 32kHz if we have one */ regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 124f9f0ef1ac..37766b547b9d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,8 @@ struct arizona_fll { unsigned int fref; unsigned int fout; + int sync_src; + unsigned int sync_freq; int ref_src; unsigned int ref_freq; -- cgit v1.2.3 From d122d6c974e35c940a638c26aa70bea363141d27 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:36 +0000 Subject: ASoC: arizona: Factor out check for enabled FLL In preparation for additional features on the FLL this patch factors out the code which checks if an FLL is currently enabled into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 03076efa4d9e..4640bccbfba2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1074,12 +1074,27 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } +static bool arizona_is_enabled_fll(struct arizona_fll *fll) +{ + struct arizona *arizona = fll->arizona; + unsigned int reg; + int ret; + + ret = regmap_read(arizona->regmap, fll->base + 1, ®); + if (ret != 0) { + arizona_fll_err(fll, "Failed to read current state: %d\n", + ret); + return ret; + } + + return reg & ARIZONA_FLL1_ENA; +} + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { struct arizona *arizona = fll->arizona; struct arizona_fll_cfg ref, sync; - unsigned int reg; bool ena; int ret; @@ -1111,13 +1126,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; } - ret = regmap_read(arizona->regmap, fll->base + 1, ®); - if (ret != 0) { - arizona_fll_err(fll, "Failed to read current state: %d\n", - ret); - return ret; - } - ena = reg & ARIZONA_FLL1_ENA; + ena = arizona_is_enabled_fll(fll); if (Fout) { regmap_update_bits(arizona->regmap, fll->base + 5, -- cgit v1.2.3 From 7604054e13897c2da3570e33a67ecb76462212d8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:37 +0000 Subject: ASoC: arizona: Factor out FLL disable In preparation for additional features on the FLL this patch factors out the code for disabling an FLL into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 4640bccbfba2..a8821a819adc 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1090,6 +1090,20 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } +static void arizona_disable_fll(struct arizona_fll *fll) +{ + struct arizona *arizona = fll->arizona; + bool change; + + regmap_update_bits_check(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, 0, &change); + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0); + + if (change) + pm_runtime_put_autosuspend(arizona->dev); +} + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { @@ -1156,13 +1170,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); } else { - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0); - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, 0); - - if (ena) - pm_runtime_put_autosuspend(arizona->dev); + arizona_disable_fll(fll); } fll->fref = Fref; -- cgit v1.2.3 From 357228153b4a158bdeb05f1c46ee13ef60a675a6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:38 +0000 Subject: ASoC: arizona: Factor out FLL enable In preparation for additional features on the FLL this patch factors out the code for enabling an FLL into a seperate function. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 66 +++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a8821a819adc..e770945fa019 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1090,6 +1090,41 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } +static void arizona_enable_fll(struct arizona_fll *fll, + struct arizona_fll_cfg *ref, + struct arizona_fll_cfg *sync) +{ + struct arizona *arizona = fll->arizona; + int ret; + + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, sync, + fll->sync_src); + + if (!arizona_is_enabled_fll(fll)) + pm_runtime_get(arizona->dev); + + /* Clear any pending completions */ + try_wait_for_completion(&fll->ok); + + regmap_update_bits(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); + if (fll->sync_src >= 0) + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, + ARIZONA_FLL1_SYNC_ENA); + + ret = wait_for_completion_timeout(&fll->ok, + msecs_to_jiffies(250)); + if (ret == 0) + arizona_fll_warn(fll, "Timed out waiting for lock\n"); +} + static void arizona_disable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; @@ -1107,9 +1142,7 @@ static void arizona_disable_fll(struct arizona_fll *fll) int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - struct arizona *arizona = fll->arizona; struct arizona_fll_cfg ref, sync; - bool ena; int ret; if (fll->fref == Fref && fll->fout == Fout) @@ -1140,35 +1173,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; } - ena = arizona_is_enabled_fll(fll); - if (Fout) { - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - arizona_apply_fll(arizona, fll->base, &ref, fll->ref_src); - if (fll->sync_src >= 0) - arizona_apply_fll(arizona, fll->base + 0x10, &sync, - fll->sync_src); - - if (!ena) - pm_runtime_get(arizona->dev); - - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - - regmap_update_bits(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->sync_src >= 0) - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, - ARIZONA_FLL1_SYNC_ENA); - - ret = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (ret == 0) - arizona_fll_warn(fll, "Timed out waiting for lock\n"); + arizona_enable_fll(fll, &ref, &sync); } else { arizona_disable_fll(fll); } -- cgit v1.2.3 From de1e6eedddeab2fa417c38c231d896198f903129 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:39 +0000 Subject: ASoC: arizona: Improve suppression of noop FLL updates Previously updates that only changes FLL source would be missed, this patch corrects this. We also ensures that both REFCLK and SYNCCLK frequency changes are considered, in preparation for future updates. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 16 ++++++++++------ sound/soc/codecs/arizona.h | 3 +-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e770945fa019..149e44f42f84 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1145,10 +1145,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (fll->fref == Fref && fll->fout == Fout) - return 0; - if (fll->ref_src < 0 || fll->ref_src == source) { + if (fll->sync_src == -1 && + fll->ref_src == source && fll->ref_freq == Fref && + fll->fout == Fout) + return 0; + if (Fout) { ret = arizona_calc_fll(fll, &ref, Fref, Fout); if (ret != 0) @@ -1159,6 +1161,10 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; } else { + if (fll->sync_src == source && + fll->sync_freq == Fref && fll->fout == Fout) + return 0; + if (Fout) { ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); if (ret != 0) @@ -1172,6 +1178,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_src = source; fll->sync_freq = Fref; } + fll->fout = Fout; if (Fout) { arizona_enable_fll(fll, &ref, &sync); @@ -1179,9 +1186,6 @@ int arizona_set_fll(struct arizona_fll *fll, int source, arizona_disable_fll(fll); } - fll->fref = Fref; - fll->fout = Fout; - return 0; } EXPORT_SYMBOL_GPL(arizona_set_fll); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 37766b547b9d..bedf12a527e5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -198,9 +198,8 @@ struct arizona_fll { unsigned int base; unsigned int vco_mult; struct completion ok; - unsigned int fref; - unsigned int fout; + unsigned int fout; int sync_src; unsigned int sync_freq; int ref_src; -- cgit v1.2.3 From ee929a9780605f21ad67a1ccb626baa41e038c1a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:40 +0000 Subject: ASoC: arizona: Add support for directly setting the FLL REFCLK This patch allows the REFCLK to be set directly allowing much greater flexibility in how the FLLs are configured. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 39 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 2 ++ sound/soc/codecs/wm5102.c | 6 ++++++ sound/soc/codecs/wm5102.h | 6 ++++-- sound/soc/codecs/wm5110.c | 6 ++++++ sound/soc/codecs/wm5110.h | 6 ++++-- 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 149e44f42f84..2bebfae3485f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1139,6 +1139,45 @@ static void arizona_disable_fll(struct arizona_fll *fll) pm_runtime_put_autosuspend(arizona->dev); } +int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout) +{ + struct arizona_fll_cfg ref, sync; + int ret; + + if (source < 0) + return -EINVAL; + + if (fll->ref_src == source && fll->ref_freq == Fref && + fll->fout == Fout) + return 0; + + if (Fout) { + ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (ret != 0) + return ret; + + if (fll->sync_src >= 0) { + ret = arizona_calc_fll(fll, &sync, fll->sync_freq, Fout); + if (ret != 0) + return ret; + } + } + + fll->ref_src = source; + fll->ref_freq = Fref; + fll->fout = Fout; + + if (Fout) { + arizona_enable_fll(fll, &ref, &sync); + } else { + arizona_disable_fll(fll); + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); + int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index bedf12a527e5..f2ca41f8dc83 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -211,6 +211,8 @@ struct arizona_fll { extern int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll); +extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout); extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b8d461db369f..5515d85fd82f 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1483,6 +1483,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout); case WM5102_FLL2: return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout); + case WM5102_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref, + Fout); + case WM5102_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref, + Fout); default: return -EINVAL; } diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h index d30477f3070c..adb38040f661 100644 --- a/sound/soc/codecs/wm5102.h +++ b/sound/soc/codecs/wm5102.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5102_FLL1 1 -#define WM5102_FLL2 2 +#define WM5102_FLL1 1 +#define WM5102_FLL2 2 +#define WM5102_FLL1_REFCLK 3 +#define WM5102_FLL2_REFCLK 4 #endif diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index cd17b477781d..2d9b55f57eed 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -880,6 +880,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout); case WM5110_FLL2: return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout); + case WM5110_FLL1_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref, + Fout); + case WM5110_FLL2_REFCLK: + return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref, + Fout); default: return -EINVAL; } diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h index 75e9351ccab0..e6c0cd4235c5 100644 --- a/sound/soc/codecs/wm5110.h +++ b/sound/soc/codecs/wm5110.h @@ -15,7 +15,9 @@ #include "arizona.h" -#define WM5110_FLL1 1 -#define WM5110_FLL2 2 +#define WM5110_FLL1 1 +#define WM5110_FLL2 2 +#define WM5110_FLL1_REFCLK 3 +#define WM5110_FLL2_REFCLK 4 #endif -- cgit v1.2.3 From f3f1163d19ebd5aa374e5df5372a8f932f2bd5f9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 20 Feb 2013 17:28:41 +0000 Subject: ASoC: arizona: Add convience define for clearing SYNCCLK Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 8 ++++---- sound/soc/codecs/arizona.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 2bebfae3485f..6837863b582d 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1185,7 +1185,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, int ret; if (fll->ref_src < 0 || fll->ref_src == source) { - if (fll->sync_src == -1 && + if (fll->sync_src == ARIZONA_FLL_SRC_NONE && fll->ref_src == source && fll->ref_freq == Fref && fll->fout == Fout) return 0; @@ -1196,7 +1196,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, return ret; } - fll->sync_src = -1; + fll->sync_src = ARIZONA_FLL_SRC_NONE; fll->ref_src = source; fll->ref_freq = Fref; } else { @@ -1240,7 +1240,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->id = id; fll->base = base; fll->arizona = arizona; - fll->sync_src = -1; + fll->sync_src = ARIZONA_FLL_SRC_NONE; /* Configure default refclk to 32kHz if we have one */ regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); @@ -1250,7 +1250,7 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK; break; default: - fll->ref_src = -1; + fll->ref_src = ARIZONA_FLL_SRC_NONE; } fll->ref_freq = 32768; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index f2ca41f8dc83..3f84943b23bf 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -32,6 +32,7 @@ #define ARIZONA_CLK_SRC_AIF2BCLK 0x9 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa +#define ARIZONA_FLL_SRC_NONE -1 #define ARIZONA_FLL_SRC_MCLK1 0 #define ARIZONA_FLL_SRC_MCLK2 1 #define ARIZONA_FLL_SRC_SLIMCLK 3 -- cgit v1.2.3 From ddbce97cd1798ba4661e33662c659b168e9f51ed Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 15 Feb 2013 17:27:22 +0000 Subject: ASoC: arizona: Only allow input volume updates when inputs are enabled Since we are automatically managing the mutes we may as well also manage the volume update bits, disabling volume updates while none of the inputs are active. Since we are doing this we may as well allow the volumes to ramp together so only enable volume updates once at the end of power up. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 39 +++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/arizona.h | 3 +++ sound/soc/codecs/wm5102.c | 26 +++++++++++++------------- sound/soc/codecs/wm5110.c | 34 +++++++++++++++++----------------- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6837863b582d..debd184cc706 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -332,9 +333,27 @@ const struct soc_enum arizona_ng_hold = 4, arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); +static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int i; + + if (ena) + val = ARIZONA_IN_VU; + else + val = 0; + + for (i = 0; i < priv->num_inputs; i++) + snd_soc_update_bits(codec, + ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4), + ARIZONA_IN_VU, val); +} + int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); unsigned int reg; if (w->shift % 2) @@ -343,13 +362,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->in_pending++; + break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0); + + /* If this is the last input pending then allow VU */ + priv->in_pending--; + if (priv->in_pending == 0) { + msleep(1); + arizona_in_set_vu(w->codec, 1); + } break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, - ARIZONA_IN1L_MUTE); + snd_soc_update_bits(w->codec, reg, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU, + ARIZONA_IN1L_MUTE | ARIZONA_IN_VU); break; + case SND_SOC_DAPM_POST_PMD: + /* Disable volume updates if no inputs are enabled */ + reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES); + if (reg == 0) + arizona_in_set_vu(w->codec, 0); } return 0; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 3f84943b23bf..d592adcc969c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -65,6 +65,9 @@ struct arizona_priv { int sysclk; int asyncclk; struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; + + int num_inputs; + unsigned int in_pending; }; #define ARIZONA_NUM_MIXER_INPUTS 99 diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 5515d85fd82f..44d4c69d25e5 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -973,22 +973,28 @@ SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -1599,13 +1605,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) #define WM5102_DIG_VU 0x0200 static unsigned int wm5102_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1648,6 +1647,7 @@ static int wm5102_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5102); wm5102->core.arizona = arizona; + wm5102->core.num_inputs = 6; wm5102->core.adsp[0].part = "wm5102"; wm5102->core.adsp[0].num = 1; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2d9b55f57eed..a64d3b8bc3b4 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"), SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -993,15 +1001,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) #define WM5110_DIG_VU 0x0200 static unsigned int wm5110_digital_vu[] = { - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_ADC_DIGITAL_VOLUME_2R, - ARIZONA_ADC_DIGITAL_VOLUME_3L, - ARIZONA_ADC_DIGITAL_VOLUME_3R, - ARIZONA_ADC_DIGITAL_VOLUME_4L, - ARIZONA_ADC_DIGITAL_VOLUME_4R, - ARIZONA_DAC_DIGITAL_VOLUME_1L, ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_DAC_DIGITAL_VOLUME_2L, @@ -1046,6 +1045,7 @@ static int wm5110_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm5110); wm5110->core.arizona = arizona; + wm5110->core.num_inputs = 8; for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) wm5110->fll[i].vco_mult = 3; -- cgit v1.2.3 From 1c5617fc230b399c1d84711b8a2e316199387eb9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2013 17:10:37 +0000 Subject: ASoC: arizona: Don't enable FLL on REFCLK configuration Enabling the FLL when REFCLK is being configured is not what the user would expect and can cause issues if SYNCCLK has no specified frequency. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index debd184cc706..e456cb4b196e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1183,17 +1183,17 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (source < 0) return -EINVAL; - if (fll->ref_src == source && fll->ref_freq == Fref && - fll->fout == Fout) + if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (Fout) { - ret = arizona_calc_fll(fll, &ref, Fref, Fout); + if (fll->fout) { + ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); if (ret != 0) return ret; if (fll->sync_src >= 0) { - ret = arizona_calc_fll(fll, &sync, fll->sync_freq, Fout); + ret = arizona_calc_fll(fll, &sync, fll->sync_freq, + fll->fout); if (ret != 0) return ret; } @@ -1201,12 +1201,9 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; - fll->fout = Fout; - if (Fout) { + if (fll->fout) { arizona_enable_fll(fll, &ref, &sync); - } else { - arizona_disable_fll(fll); } return 0; -- cgit v1.2.3 From f6a75d95048895ed3fa6758e1ec1238d945472c7 Mon Sep 17 00:00:00 2001 From: Zoltan Puskas Date: Wed, 20 Feb 2013 17:31:35 +0100 Subject: ASoC: atmel: Add slave mode support to SSC in DSP Mode A Add previously unsupported slave mode to the SSC peripheral when using DSP/PCM Mode A format on the Atmel ARM platform. Signed-off-by: Zoltan Puskas Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index e13580d6c476..94da62345a27 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + /* + * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. + * + * Data is transferred on first BCLK after LRC pulse rising + * edge.If stereo, the right channel data is contiguous with + * the left channel data. + */ + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, SSC_START_RISING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_PIN); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, SSC_START_RISING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + default: printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", ssc_p->daifmt); -- cgit v1.2.3 From f790b94d7867fb0555f91ae920b9001b42ae38a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 25 Feb 2013 00:40:09 -0800 Subject: ASoC: core: tidyup snd_soc_register_codec() fail case kfree() on snd_soc_register_codec() was summarized to one place. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b7e84a7cd9ee..a872be1ee44d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4022,8 +4022,8 @@ int snd_soc_register_codec(struct device *dev, /* create CODEC component name */ codec->name = fmt_single_name(dev, &codec->id); if (codec->name == NULL) { - kfree(codec); - return -ENOMEM; + ret = -ENOMEM; + goto fail_codec; } if (codec_drv->compress_type) @@ -4062,7 +4062,7 @@ int snd_soc_register_codec(struct device *dev, reg_size, GFP_KERNEL); if (!codec->reg_def_copy) { ret = -ENOMEM; - goto fail; + goto fail_codec_name; } } } @@ -4096,8 +4096,9 @@ int snd_soc_register_codec(struct device *dev, dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); return 0; -fail: +fail_codec_name: kfree(codec->name); +fail_codec: kfree(codec); return ret; } -- cgit v1.2.3 From 5acd7dfbd7851446fb1d2c947661d365e4c635a0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 25 Feb 2013 00:40:40 -0800 Subject: ASoC: core: use snd_soc_register_dais() on codec snd_soc_register_dais() considers dai counts inside. snd_soc_register_codec() does not need to care for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a872be1ee44d..e02c374d2243 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4086,11 +4086,10 @@ int snd_soc_register_codec(struct device *dev, mutex_unlock(&client_mutex); /* register any DAIs */ - if (num_dai) { - ret = snd_soc_register_dais(dev, dai_drv, num_dai); - if (ret < 0) - dev_err(codec->dev, "ASoC: Failed to regster" - " DAIs: %d\n", ret); + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto fail_codec_name; } dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); @@ -4112,7 +4111,6 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec); void snd_soc_unregister_codec(struct device *dev) { struct snd_soc_codec *codec; - int i; list_for_each_entry(codec, &codec_list, list) { if (dev == codec->dev) @@ -4121,9 +4119,7 @@ void snd_soc_unregister_codec(struct device *dev) return; found: - if (codec->num_dai) - for (i = 0; i < codec->num_dai; i++) - snd_soc_unregister_dai(dev); + snd_soc_unregister_dais(dev, codec->num_dai); mutex_lock(&client_mutex); list_del(&codec->list); -- cgit v1.2.3 From 2952b27e2e463b28d5c0f04000f96b968137ca42 Mon Sep 17 00:00:00 2001 From: Michal Bachraty Date: Thu, 28 Feb 2013 16:07:08 +0100 Subject: ASoC: davinci-mcasp: Add support for multichannel playback Davinci McASP has support for I2S multichannel playback. For I2S playback/receive, each serializer is capable to play 2 channels (L/R) audio data.Serializer function (Playback-receive-none) is configured in DT, depending on hardware specification. It is possible to play less channels than configured in DT. For that purpose,only specific number of active serializers are enabled. McASP FIFO need to have DMA transfer Bcnt set to number of enabled serializers, otherwise no data are transfered to McASP and Alsa generates "DMA/IRQ playback write error (DMA or IRQ trouble?)" error. For TDM mode, McASP is capable to play or receive 32 channels for one serializer. McAsp has support for max 16 serializer, therefore max channels is 32 * 8. Signed-off-by: Michal Bachraty Tested-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 66 ++++++++++++++++++++++++++++++++++----- sound/soc/davinci/davinci-pcm.c | 16 +++++----- sound/soc/davinci/davinci-pcm.h | 1 + 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 9321e5c9d8c1..5cd85a879579 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -235,6 +235,10 @@ #define DISMOD (val)(val<<2) #define TXSTATE BIT(4) #define RXSTATE BIT(5) +#define SRMOD_MASK 3 +#define SRMOD_INACTIVE 0 +#define SRMOD_TX 1 +#define SRMOD_RX 2 /* * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits @@ -657,12 +661,15 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, return 0; } -static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) +static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream, + int channels) { int i; u8 tx_ser = 0; u8 rx_ser = 0; - + u8 ser; + u8 slots = dev->tdm_slots; + u8 max_active_serializers = (channels + slots - 1) / slots; /* Default configuration */ mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); @@ -679,17 +686,43 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) RXDATADMADIS); } + for (i = 0; i < dev->num_serializer; i++) { + if (dev->serial_dir[i] == TX_MODE) + tx_ser++; + if (dev->serial_dir[i] == RX_MODE) + rx_ser++; + } + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ser = tx_ser; + else + ser = rx_ser; + + if (ser < max_active_serializers) { + dev_warn(dev->dev, "stream has more channels (%d) than are " + "enabled in mcasp (%d)\n", channels, ser * slots); + return -EINVAL; + } + + tx_ser = 0; + rx_ser = 0; + for (i = 0; i < dev->num_serializer; i++) { mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), dev->serial_dir[i]); - if (dev->serial_dir[i] == TX_MODE) { + if (dev->serial_dir[i] == TX_MODE && + tx_ser < max_active_serializers) { mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); tx_ser++; - } else if (dev->serial_dir[i] == RX_MODE) { + } else if (dev->serial_dir[i] == RX_MODE && + rx_ser < max_active_serializers) { mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); rx_ser++; + } else { + mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), + SRMOD_INACTIVE, SRMOD_MASK); } } @@ -729,6 +762,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); } } + + return 0; } static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) @@ -812,8 +847,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, &dev->dma_params[substream->stream]; int word_length; u8 fifo_level; + u8 slots = dev->tdm_slots; + int channels; + struct snd_interval *pcm_channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels = pcm_channels->min; - davinci_hw_common_param(dev, substream->stream); + if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL) + return -EINVAL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fifo_level = dev->txnumevt; else @@ -862,6 +903,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, dma_params->acnt = dma_params->data_type; dma_params->fifo_level = fifo_level; + dma_params->active_serializers = (channels + slots - 1) / slots; davinci_config_channel_size(dev, word_length); return 0; @@ -936,13 +978,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { .name = "davinci-mcasp.0", .playback = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, .capture = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, @@ -1015,8 +1057,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->op_mode = val; ret = of_property_read_u32(np, "tdm-slots", &val); - if (ret >= 0) + if (ret >= 0) { + if (val < 2 || val > 32) { + dev_err(&pdev->dev, + "tdm-slots must be in rage [2-32]\n"); + ret = -EINVAL; + goto nodata; + } + pdata->tdm_slots = val; + } ret = of_property_read_u32(np, "num-serializer", &val); if (ret >= 0) diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index afab81f844ae..078031d61167 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -181,6 +181,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) unsigned short acnt; unsigned int count; unsigned int fifo_level; + unsigned char serializers = prtd->params->active_serializers; period_size = snd_pcm_lib_period_bytes(substream); dma_offset = prtd->period * period_size; @@ -194,14 +195,14 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) data_type = prtd->params->data_type; count = period_size / data_type; if (fifo_level) - count /= fifo_level; + count /= fifo_level * serializers; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = dma_pos; dst = prtd->params->dma_addr; src_bidx = data_type; - dst_bidx = 0; - src_cidx = data_type * fifo_level; + dst_bidx = 4; + src_cidx = data_type * fifo_level * serializers; dst_cidx = 0; } else { src = prtd->params->dma_addr; @@ -209,7 +210,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) src_bidx = 0; dst_bidx = data_type; src_cidx = 0; - dst_cidx = data_type * fifo_level; + dst_cidx = data_type * fifo_level * serializers; } acnt = prtd->params->acnt; @@ -223,9 +224,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0, ASYNC); else - edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, - count, fifo_level, - ABSYNC); + edma_set_transfer_params(prtd->asp_link[0], acnt, + fifo_level * serializers, + count, fifo_level * serializers, + ABSYNC); } static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index b6ef7039dd09..32d7634d7b26 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -27,6 +27,7 @@ struct davinci_pcm_dma_params { unsigned char data_type; /* xfer data type */ unsigned char convert_mono_stereo; unsigned int fifo_level; + unsigned char active_serializers; /* num. of active audio serializers */ }; int davinci_soc_platform_register(struct device *dev); -- cgit v1.2.3 From c751a1f49b3fbdce0fbbb2c9b56544a7e6833fff Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 15 Feb 2013 08:55:10 -0800 Subject: ASoC: max98088: Add TLV data for volume controls. Specify volumes as defined in the MAX98088/9 data sheet. Allows ALSA lib snd_mixer_selem_get_playback_dB_range and related functions to work. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index a4c16fd70f77..3a7b7fd14e3e 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -739,14 +739,32 @@ static const unsigned int max98088_micboost_tlv[] = { 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), }; +static const unsigned int max98088_hp_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), + 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), + 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), + 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), + 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), +}; + +static const unsigned int max98088_spk_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), + 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), + 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), + 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), +}; + static const struct snd_kcontrol_new max98088_snd_controls[] = { - SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L, - M98088_REG_3A_LVL_HP_R, 0, 31, 0), - SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L, - M98088_REG_3E_LVL_SPK_R, 0, 31, 0), - SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L, - M98088_REG_3C_LVL_REC_R, 0, 31, 0), + SOC_DOUBLE_R_TLV("Headphone Volume", M98088_REG_39_LVL_HP_L, + M98088_REG_3A_LVL_HP_R, 0, 31, 0, max98088_hp_tlv), + SOC_DOUBLE_R_TLV("Speaker Volume", M98088_REG_3D_LVL_SPK_L, + M98088_REG_3E_LVL_SPK_R, 0, 31, 0, max98088_spk_tlv), + SOC_DOUBLE_R_TLV("Receiver Volume", M98088_REG_3B_LVL_REC_L, + M98088_REG_3C_LVL_REC_R, 0, 31, 0, max98088_spk_tlv), SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L, M98088_REG_3A_LVL_HP_R, 7, 1, 1), -- cgit v1.2.3 From f314cbe84fd81082a286af685c59c2dc4048bc77 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Feb 2013 17:02:10 +0530 Subject: ASoC: max98090: Remove unneeded version.h header include version.h header file inclusion is not required as detected by versioncheck. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index fc176044994d..9ea73aa71198 100755 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -23,8 +23,6 @@ #include #include "max98090.h" -#include - #define DEBUG #define EXTMIC_METHOD #define EXTMIC_METHOD_TEST -- cgit v1.2.3 From a3a6cc84652d82ff795c519c6187d37baa1d9697 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Feb 2013 17:02:11 +0530 Subject: ASoC: max98090: Convert to devm_regmap_init_i2c() devm_regmap_init_i2c() is device managed and makes error handling and code cleanup simpler. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 9ea73aa71198..fef370e03305 100755 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2322,7 +2322,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c, max98090->pdata = i2c->dev.platform_data; max98090->irq = i2c->irq; - max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap); + max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); if (IS_ERR(max98090->regmap)) { ret = PTR_ERR(max98090->regmap); dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); @@ -2332,18 +2332,13 @@ static int max98090_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98090, max98090_dai, ARRAY_SIZE(max98090_dai)); - if (ret < 0) - regmap_exit(max98090->regmap); - err_enable: return ret; } static int max98090_i2c_remove(struct i2c_client *client) { - struct max98090_priv *max98090 = dev_get_drvdata(&client->dev); snd_soc_unregister_codec(&client->dev); - regmap_exit(max98090->regmap); return 0; } -- cgit v1.2.3 From 3e12af7e139275e5822383e210c86e0ff1ea185c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Feb 2013 17:02:12 +0530 Subject: ASoC: max98090: Make struct dev_pm_ops const Silences the following checkpatch warning: WARNING: struct dev_pm_ops should normally be const. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index fef370e03305..1cf017f2f587 100755 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2362,7 +2362,7 @@ static int max98090_runtime_suspend(struct device *dev) return 0; } -static struct dev_pm_ops max98090_pm = { +static const struct dev_pm_ops max98090_pm = { SET_RUNTIME_PM_OPS(max98090_runtime_suspend, max98090_runtime_resume, NULL) }; -- cgit v1.2.3 From 4ca74feb6ceb3031e8cf9ef88dedb3ebb984a59a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 21 Feb 2013 12:24:59 +0530 Subject: ASoC: max98090: Fix checkpatch errors related to spacing Fixes the following type of checkpatch errors: ERROR: "foo * bar" should be "foo *bar" Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1cf017f2f587..89f83f8e56b2 100755 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -507,16 +507,16 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, return 0; } -static const char * max98090_perf_pwr_text[] = +static const char *max98090_perf_pwr_text[] = { "High Performance", "Low Power" }; -static const char * max98090_pwr_perf_text[] = +static const char *max98090_pwr_perf_text[] = { "Low Power", "High Performance" }; static const struct soc_enum max98090_vcmbandgap_enum = SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); -static const char * max98090_osr128_text[] = { "64*fs", "128*fs" }; +static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; static const struct soc_enum max98090_osr128_enum = SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, @@ -533,28 +533,28 @@ static const struct soc_enum max98090_filter_dmic34mode_enum = M98090_FLT_DMIC34MODE_SHIFT, ARRAY_SIZE(max98090_mode_text), max98090_mode_text); -static const char * max98090_drcatk_text[] = +static const char *max98090_drcatk_text[] = { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; static const struct soc_enum max98090_drcatk_enum = SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); -static const char * max98090_drcrls_text[] = +static const char *max98090_drcrls_text[] = { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; static const struct soc_enum max98090_drcrls_enum = SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); -static const char * max98090_alccmp_text[] = +static const char *max98090_alccmp_text[] = { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; static const struct soc_enum max98090_alccmp_enum = SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); -static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; +static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; static const struct soc_enum max98090_drcexp_enum = SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, @@ -857,7 +857,7 @@ static const struct soc_enum mic2_mux_enum = static const struct snd_kcontrol_new max98090_mic2_mux = SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); -static const char * max98090_micpre_text[] = { "Off", "On" }; +static const char *max98090_micpre_text[] = { "Off", "On" }; static const struct soc_enum max98090_pa1en_enum = SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, -- cgit v1.2.3 From 959b6250dbf8398e3c63544f771ff1682a09987e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 21 Feb 2013 12:25:00 +0530 Subject: ASoC: max98090: Remove unnecessary braces Braces are not required for single line statements. Silences the following checkpatch warnings: WARNING: braces {} are not necessary for single statement blocks. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 89f83f8e56b2..ce0d36412c97 100755 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1701,9 +1701,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, * seen for the case of TDM mode. The remaining cases have * normal logic. */ - if (max98090->tdm_slots > 1) { + if (max98090->tdm_slots > 1) regval ^= M98090_BCI_MASK; - } snd_soc_write(codec, M98090_REG_INTERFACE_FORMAT, regval); @@ -2057,17 +2056,14 @@ static irqreturn_t max98090_interrupt(int irq, void *data) if (!active) return IRQ_NONE; - if (active & M98090_CLD_MASK) { + if (active & M98090_CLD_MASK) dev_err(codec->dev, "M98090_CLD_MASK\n"); - } - if (active & M98090_SLD_MASK) { + if (active & M98090_SLD_MASK) dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - } - if (active & M98090_ULK_MASK) { + if (active & M98090_ULK_MASK) dev_err(codec->dev, "M98090_ULK_MASK\n"); - } if (active & M98090_JDET_MASK) { dev_dbg(codec->dev, "M98090_JDET_MASK\n"); @@ -2078,13 +2074,11 @@ static irqreturn_t max98090_interrupt(int irq, void *data) msecs_to_jiffies(100)); } - if (active & M98090_DRCACT_MASK) { + if (active & M98090_DRCACT_MASK) dev_dbg(codec->dev, "M98090_DRCACT_MASK\n"); - } - if (active & M98090_DRCCLP_MASK) { + if (active & M98090_DRCCLP_MASK) dev_err(codec->dev, "M98090_DRCCLP_MASK\n"); - } return IRQ_HANDLED; } -- cgit v1.2.3 From ddd17531ad9089ca1a758cd53fb698f396665cb5 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Wed, 13 Feb 2013 08:21:54 +0100 Subject: ASoC: omap-mcpdm: Clean up with devm_* function Clean up McPDM driver with devm_ function. Signed-off-by: Sebastien Guiriec Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 5ca11bdac21e..079f277cdba4 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -369,7 +369,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) pm_runtime_get_sync(mcpdm->dev); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); - ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, + ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM", (void *)mcpdm); pm_runtime_put_sync(mcpdm->dev); @@ -389,7 +389,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - free_irq(mcpdm->irq, (void *)mcpdm); pm_runtime_disable(mcpdm->dev); return 0; @@ -465,14 +464,11 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) if (res == NULL) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), "McPDM")) - return -EBUSY; - - mcpdm->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!mcpdm->io_base) + mcpdm->io_base = devm_request_and_ioremap(&pdev->dev, res); + if (!mcpdm->io_base) { + dev_err(&pdev->dev, "cannot remap\n"); return -ENOMEM; + } mcpdm->irq = platform_get_irq(pdev, 0); if (mcpdm->irq < 0) -- cgit v1.2.3 From 4f224c612438e0c2067594636c6998ce5048d228 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Wed, 13 Feb 2013 08:22:07 +0100 Subject: ASoC: omap-dmic: Clean up with devm_request_and_ioremap Clean up dmic code with devm_request_and_ioremap function. Signed-off-by: Sebastien Guiriec Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-dmic.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index ba49ccd9eed9..77e9e7e68edc 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -493,16 +493,9 @@ static int asoc_dmic_probe(struct platform_device *pdev) goto err_put_clk; } - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_err(dmic->dev, "memory region already claimed\n"); - ret = -ENODEV; - goto err_put_clk; - } - - dmic->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + dmic->io_base = devm_request_and_ioremap(&pdev->dev, res); if (!dmic->io_base) { + dev_err(&pdev->dev, "cannot remap\n"); ret = -ENOMEM; goto err_put_clk; } -- cgit v1.2.3 From d686500ae87275ed58a074f9e5e8b35b9afe30d8 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 18 Feb 2013 19:59:34 -0800 Subject: ASoC: si476x: Convert SI476X codec to use regmap The latest radio and MFD drivers for SI476X radio chips use regmap API to provide access to the registers and allow for caching of their values when the actual chip is powered off. Convert the codec driver to do the same, so it would not loose the settings when the radio driver powers the chip down. Signed-off-by: Andrey Smirnov Signed-off-by: Mark Brown --- sound/soc/codecs/si476x.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index f2d61a187830..30aebbe6815e 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -45,13 +45,23 @@ static unsigned int si476x_codec_read(struct snd_soc_codec *codec, unsigned int reg) { int err; + unsigned int val; struct si476x_core *core = codec->control_data; si476x_core_lock(core); - err = si476x_core_cmd_get_property(core, reg); + if (!si476x_core_is_powered_up(core)) + regcache_cache_only(core->regmap, true); + + err = regmap_read(core->regmap, reg, &val); + + if (!si476x_core_is_powered_up(core)) + regcache_cache_only(core->regmap, false); si476x_core_unlock(core); - return err; + if (err < 0) + return err; + + return val; } static int si476x_codec_write(struct snd_soc_codec *codec, @@ -61,7 +71,13 @@ static int si476x_codec_write(struct snd_soc_codec *codec, struct si476x_core *core = codec->control_data; si476x_core_lock(core); - err = si476x_core_cmd_set_property(core, reg, val); + if (!si476x_core_is_powered_up(core)) + regcache_cache_only(core->regmap, true); + + err = regmap_write(core->regmap, reg, val); + + if (!si476x_core_is_powered_up(core)) + regcache_cache_only(core->regmap, false); si476x_core_unlock(core); return err; -- cgit v1.2.3 From 06d7c13325228a2272e21caa4aa60805bc4d0fe4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 18 Feb 2013 19:59:35 -0800 Subject: ASoC: si476x: Cosmetic changes to SI476X codec driver - Add appropriate license header - Change email address in MODULE_AUTHOR - Remove trailing whitespaces Signed-off-by: Andrey Smirnov Signed-off-by: Mark Brown --- sound/soc/codecs/si476x.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 30aebbe6815e..68b648aabdb9 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -1,3 +1,22 @@ +/* + * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * 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; version 2 of the License. + * + * 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. + * + */ + #include #include #include @@ -156,7 +175,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, dev_err(codec_dai->codec->dev, "Failed to set output format\n"); return err; } - + return 0; } @@ -197,7 +216,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream, err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK, - (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | + (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); if (err < 0) { dev_err(dai->codec->dev, "Failed to set output width\n"); @@ -266,6 +285,6 @@ static struct platform_driver si476x_platform_driver = { }; module_platform_driver(si476x_platform_driver); -MODULE_AUTHOR("Andrey Smirnov "); +MODULE_AUTHOR("Andrey Smirnov "); MODULE_DESCRIPTION("ASoC Si4761/64 codec driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 69de6be70e611c8165b9b5c16d69574d13f2a3b0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:30 -0700 Subject: ASoC: tegra: assume CONFIG_OF in tegra_asoc_utils_init Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_asoc_utils.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index ba419f86384d..49861c6ed874 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -176,11 +176,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; else if (of_machine_is_compatible("nvidia,tegra30")) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; - else if (!dev->of_node) - /* non-DT is always Tegra20 */ - data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; else - /* DT boot, but unknown SoC */ return -EINVAL; data->clk_pll_a = clk_get_sys(NULL, "pll_a"); -- cgit v1.2.3 From bddd7d0230deb3fbc2cb32e0af04f7cf46397e9e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:31 -0700 Subject: ASoC: tegra_wm8753: minor cleanup Various minor cleanups so that the probe() body more closely resembles other drivers, for easier comparison. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_wm8753.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index c8ef88a67c59..f87fc53e9b8c 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -124,6 +124,7 @@ static struct snd_soc_card snd_soc_tegra_wm8753 = { static int tegra_wm8753_driver_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_wm8753; struct tegra_wm8753 *machine; int ret; @@ -132,8 +133,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) GFP_KERNEL); if (!machine) { dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } card->dev = &pdev->dev; @@ -148,8 +148,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) if (ret) goto err; - tegra_wm8753_dai.codec_of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,audio-codec", 0); + tegra_wm8753_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); if (!tegra_wm8753_dai.codec_of_node) { dev_err(&pdev->dev, "Property 'nvidia,audio-codec' missing or invalid\n"); @@ -157,8 +157,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) goto err; } - tegra_wm8753_dai.cpu_of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,i2s-controller", 0); + tegra_wm8753_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); if (!tegra_wm8753_dai.cpu_of_node) { dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing or invalid\n"); @@ -166,8 +166,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) goto err; } - tegra_wm8753_dai.platform_of_node = - tegra_wm8753_dai.cpu_of_node; + tegra_wm8753_dai.platform_of_node = tegra_wm8753_dai.cpu_of_node; ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) -- cgit v1.2.3 From 078e027386b2fdeb154393eb87a5b325d0937ed9 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:32 -0700 Subject: ASoC: tegra_wm9712: assume CONFIG_OF Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. Signed-off-by: Stephen Warren Acked-by: Lucas Stach Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_wm9712.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 68d42403d9b5..ce98e5b28360 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -79,11 +79,6 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev) struct tegra_wm9712 *machine; int ret; - if (!pdev->dev.of_node) { - dev_err(&pdev->dev, "No platform data supplied\n"); - return -EINVAL; - } - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712), GFP_KERNEL); if (!machine) { -- cgit v1.2.3 From f726536fc08db7a209e35b011883bbaee8e93db7 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:33 -0700 Subject: ASoC: tegra_alc5632: assume CONFIG_OF, and other cleanup Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. Also, various minor cleanups so that the probe() body more closely resembles other drivers, for easier comparison. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_alc5632.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index c80adb9da472..48d05d9e1002 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -161,20 +161,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev) sizeof(struct tegra_alc5632), GFP_KERNEL); if (!alc5632) { dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, alc5632); - if (!(pdev->dev.of_node)) { - dev_err(&pdev->dev, "Must be instantiated using device tree\n"); - ret = -EINVAL; - goto err; - } - alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); if (alc5632->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -197,11 +190,11 @@ static int tegra_alc5632_probe(struct platform_device *pdev) goto err; } - tegra_alc5632_dai.cpu_of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,i2s-controller", 0); + tegra_alc5632_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); if (!tegra_alc5632_dai.cpu_of_node) { dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); + "Property 'nvidia,i2s-controller' missing or invalid\n"); ret = -EINVAL; goto err; } -- cgit v1.2.3 From bd85a06c2b81d9947426d48125ee7a96a6c67e3c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:34 -0700 Subject: ASoC: tegra trimslice: assume CONFIG_OF, and other cleanup Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. Also, some minor changes so that the probe() body more closely resembles other drivers, for easier comparison. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/trimslice.c | 56 +++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 7fcf6c2297db..05c68aab5cf0 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -97,9 +97,6 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = { static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { .name = "TLV320AIC23", .stream_name = "AIC23", - .codec_name = "tlv320aic23-codec.2-001a", - .platform_name = "tegra20-i2s.0", - .cpu_dai_name = "tegra20-i2s.0", .codec_dai_name = "tlv320aic23-hifi", .ops = &trimslice_asoc_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | @@ -122,6 +119,7 @@ static struct snd_soc_card snd_soc_trimslice = { static int tegra_snd_trimslice_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_trimslice; struct tegra_trimslice *trimslice; int ret; @@ -130,44 +128,38 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev) GFP_KERNEL); if (!trimslice) { dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); - ret = -ENOMEM; + return -ENOMEM; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, trimslice); + + trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!trimslice_tlv320aic23_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; goto err; } - if (pdev->dev.of_node) { - trimslice_tlv320aic23_dai.codec_name = NULL; - trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,audio-codec", 0); - if (!trimslice_tlv320aic23_dai.codec_of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - trimslice_tlv320aic23_dai.cpu_dai_name = NULL; - trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,i2s-controller", 0); - if (!trimslice_tlv320aic23_dai.cpu_of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - trimslice_tlv320aic23_dai.platform_name = NULL; - trimslice_tlv320aic23_dai.platform_of_node = - trimslice_tlv320aic23_dai.cpu_of_node; + trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!trimslice_tlv320aic23_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; } + trimslice_tlv320aic23_dai.platform_of_node = + trimslice_tlv320aic23_dai.cpu_of_node; + ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); if (ret) goto err; - card->dev = &pdev->dev; - platform_set_drvdata(pdev, card); - snd_soc_card_set_drvdata(card, trimslice); - ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", -- cgit v1.2.3 From 8f5f5e0f459d37273f841e3f8da38b4e242c8e94 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:35 -0700 Subject: ASoC: tegra_wm8903: assume CONFIG_OF, remove platform data Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. This allows removal of the hard-coded Harmony ASoC mapping table, since Harmony only boots with DT now. All board-specific configuration now comes from device tree, so there is no need to have a platform_data structure. Rework the driver to parse the device tree directly into struct tegra_wm8903. Also some slight re-ordering of probe() so that the code more closely resembles other drivers for easier comparison. Inparticular, the GPIO DT parsing and initial programming are moved together for each GPIO. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/tegra_wm8903.h | 26 ------ sound/soc/tegra/tegra_wm8903.c | 179 ++++++++++++++++------------------------- 2 files changed, 70 insertions(+), 135 deletions(-) delete mode 100644 include/sound/tegra_wm8903.h diff --git a/include/sound/tegra_wm8903.h b/include/sound/tegra_wm8903.h deleted file mode 100644 index 57b202ee97c3..000000000000 --- a/include/sound/tegra_wm8903.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2011 NVIDIA, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#ifndef __SOUND_TEGRA_WM38903_H -#define __SOUND_TEGRA_WM38903_H - -struct tegra_wm8903_platform_data { - int gpio_spkr_en; - int gpio_hp_det; - int gpio_hp_mute; - int gpio_int_mic_en; - int gpio_ext_mic_en; -}; - -#endif diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index bbd79bf56303..4ac73730d79a 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -39,7 +39,6 @@ #include #include #include -#include #include "../codecs/wm8903.h" @@ -48,7 +47,11 @@ #define DRV_NAME "tegra-snd-wm8903" struct tegra_wm8903 { - struct tegra_wm8903_platform_data pdata; + int gpio_spkr_en; + int gpio_hp_det; + int gpio_hp_mute; + int gpio_int_mic_en; + int gpio_ext_mic_en; struct tegra_asoc_utils_data util_data; }; @@ -129,12 +132,11 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = &machine->pdata; - if (!gpio_is_valid(pdata->gpio_spkr_en)) + if (!gpio_is_valid(machine->gpio_spkr_en)) return 0; - gpio_set_value_cansleep(pdata->gpio_spkr_en, + gpio_set_value_cansleep(machine->gpio_spkr_en, SND_SOC_DAPM_EVENT_ON(event)); return 0; @@ -146,12 +148,11 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = &machine->pdata; - if (!gpio_is_valid(pdata->gpio_hp_mute)) + if (!gpio_is_valid(machine->gpio_hp_mute)) return 0; - gpio_set_value_cansleep(pdata->gpio_hp_mute, + gpio_set_value_cansleep(machine->gpio_hp_mute, !SND_SOC_DAPM_EVENT_ON(event)); return 0; @@ -163,17 +164,6 @@ static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), }; -static const struct snd_soc_dapm_route harmony_audio_map[] = { - {"Headphone Jack", NULL, "HPOUTR"}, - {"Headphone Jack", NULL, "HPOUTL"}, - {"Int Spk", NULL, "ROP"}, - {"Int Spk", NULL, "RON"}, - {"Int Spk", NULL, "LOP"}, - {"Int Spk", NULL, "LON"}, - {"Mic Jack", NULL, "MICBIAS"}, - {"IN1L", NULL, "Mic Jack"}, -}; - static const struct snd_kcontrol_new tegra_wm8903_controls[] = { SOC_DAPM_PIN_SWITCH("Int Spk"), }; @@ -185,10 +175,9 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = &machine->pdata; - if (gpio_is_valid(pdata->gpio_hp_det)) { - tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; + if (gpio_is_valid(machine->gpio_hp_det)) { + tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det; snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack); snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, @@ -226,9 +215,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card) static struct snd_soc_dai_link tegra_wm8903_dai = { .name = "WM8903", .stream_name = "WM8903 PCM", - .codec_name = "wm8903.0-001a", - .platform_name = "tegra20-i2s.0", - .cpu_dai_name = "tegra20-i2s.0", .codec_dai_name = "wm8903-hifi", .init = tegra_wm8903_init, .ops = &tegra_wm8903_ops, @@ -257,96 +243,25 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &snd_soc_tegra_wm8903; struct tegra_wm8903 *machine; - struct tegra_wm8903_platform_data *pdata; int ret; - if (!pdev->dev.platform_data && !pdev->dev.of_node) { - dev_err(&pdev->dev, "No platform data supplied\n"); - return -EINVAL; - } - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903), GFP_KERNEL); if (!machine) { dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } - pdata = &machine->pdata; card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); - if (pdev->dev.platform_data) { - memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); - } else if (np) { - pdata->gpio_spkr_en = of_get_named_gpio(np, - "nvidia,spkr-en-gpios", 0); - if (pdata->gpio_spkr_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - - pdata->gpio_hp_mute = of_get_named_gpio(np, - "nvidia,hp-mute-gpios", 0); - if (pdata->gpio_hp_mute == -EPROBE_DEFER) - return -EPROBE_DEFER; - - pdata->gpio_hp_det = of_get_named_gpio(np, - "nvidia,hp-det-gpios", 0); - if (pdata->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - pdata->gpio_int_mic_en = of_get_named_gpio(np, - "nvidia,int-mic-en-gpios", 0); - if (pdata->gpio_int_mic_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - - pdata->gpio_ext_mic_en = of_get_named_gpio(np, - "nvidia,ext-mic-en-gpios", 0); - if (pdata->gpio_ext_mic_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - } - - if (np) { - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, - "nvidia,audio-routing"); - if (ret) - goto err; - - tegra_wm8903_dai.codec_name = NULL; - tegra_wm8903_dai.codec_of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_wm8903_dai.codec_of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - tegra_wm8903_dai.cpu_dai_name = NULL; - tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_wm8903_dai.cpu_of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - tegra_wm8903_dai.platform_name = NULL; - tegra_wm8903_dai.platform_of_node = - tegra_wm8903_dai.cpu_of_node; - } else { - card->dapm_routes = harmony_audio_map; - card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); - } - - if (gpio_is_valid(pdata->gpio_spkr_en)) { - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en, + machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios", + 0); + if (machine->gpio_spkr_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_spkr_en)) { + ret = devm_gpio_request_one(&pdev->dev, machine->gpio_spkr_en, GPIOF_OUT_INIT_LOW, "spkr_en"); if (ret) { dev_err(card->dev, "cannot get spkr_en gpio\n"); @@ -354,8 +269,12 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) } } - if (gpio_is_valid(pdata->gpio_hp_mute)) { - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute, + machine->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios", + 0); + if (machine->gpio_hp_mute == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_hp_mute)) { + ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_mute, GPIOF_OUT_INIT_HIGH, "hp_mute"); if (ret) { dev_err(card->dev, "cannot get hp_mute gpio\n"); @@ -363,9 +282,18 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) } } - if (gpio_is_valid(pdata->gpio_int_mic_en)) { + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + if (machine->gpio_hp_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + + machine->gpio_int_mic_en = of_get_named_gpio(np, + "nvidia,int-mic-en-gpios", 0); + if (machine->gpio_int_mic_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_int_mic_en)) { /* Disable int mic; enable signal is active-high */ - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en, + ret = devm_gpio_request_one(&pdev->dev, + machine->gpio_int_mic_en, GPIOF_OUT_INIT_LOW, "int_mic_en"); if (ret) { dev_err(card->dev, "cannot get int_mic_en gpio\n"); @@ -373,9 +301,14 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) } } - if (gpio_is_valid(pdata->gpio_ext_mic_en)) { + machine->gpio_ext_mic_en = of_get_named_gpio(np, + "nvidia,ext-mic-en-gpios", 0); + if (machine->gpio_ext_mic_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_ext_mic_en)) { /* Enable ext mic; enable signal is active-low */ - ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en, + ret = devm_gpio_request_one(&pdev->dev, + machine->gpio_ext_mic_en, GPIOF_OUT_INIT_LOW, "ext_mic_en"); if (ret) { dev_err(card->dev, "cannot get ext_mic_en gpio\n"); @@ -383,6 +316,34 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) } } + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_wm8903_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_wm8903_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_wm8903_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_wm8903_dai.platform_of_node = tegra_wm8903_dai.cpu_of_node; + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) goto err; -- cgit v1.2.3 From 21eb2693dd3bb701f831588977f92c4b63eeb132 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 26 Feb 2013 23:36:37 +0000 Subject: ASoC: wm8960: Add input boost volume control Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 9bb927325993..3fea242cbf1a 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -204,6 +204,7 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); +static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1); static const struct snd_kcontrol_new wm8960_snd_controls[] = { SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, @@ -213,6 +214,15 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, 7, 1, 0), +SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume", + WM8960_INBMIX1, 4, 7, 0, boost_tlv), +SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume", + WM8960_INBMIX1, 1, 7, 0, boost_tlv), +SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume", + WM8960_INBMIX2, 4, 7, 0, boost_tlv), +SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume", + WM8960_INBMIX2, 1, 7, 0, boost_tlv), + SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC, 0, 255, 0, dac_tlv), -- cgit v1.2.3 From dd194b48465ba9c4eef7f16a4815b7761a8172ce Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 2 Mar 2013 15:47:55 +0800 Subject: ASoC: omap: Check regulator enable for DAC on Pandora This will probably never fail but it's better style. Signed-off-by: Mark Brown Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula --- sound/soc/omap/omap3pandora.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 805512f2555a..10ced9d2e0de 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -80,12 +80,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream, static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { + int ret; + /* * The PCM1773 DAC datasheet requires 1ms delay between switching * VCC power on/off and /PD pin high/low */ if (SND_SOC_DAPM_EVENT_ON(event)) { - regulator_enable(omap3pandora_dac_reg); + ret = regulator_enable(omap3pandora_dac_reg); + if (ret) { + dev_err(w->dapm.dev, "Failed to power DAC: %d\n", ret); + return ret; + } mdelay(1); gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); } else { -- cgit v1.2.3 From ff680a173506e0f5f15c1d9c70251e7e3208c761 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 4 Mar 2013 16:00:19 +0800 Subject: ASoC: arizona: If we only have a clock to synchronise with make it REFCLK If there is only one clock active the FLL should use REFCLK rather than SYNCCLK as the clock to synchronise with since REFCLK is always required. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e456cb4b196e..0599ff8ea935 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1132,14 +1132,30 @@ static void arizona_enable_fll(struct arizona_fll *fll, struct arizona *arizona = fll->arizona; int ret; - regmap_update_bits(arizona->regmap, fll->base + 5, - ARIZONA_FLL1_OUTDIV_MASK, - ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - - arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); - if (fll->sync_src >= 0) - arizona_apply_fll(arizona, fll->base + 0x10, sync, + /* + * If we have both REFCLK and SYNCCLK then enable both, + * otherwise apply the SYNCCLK settings to REFCLK. + */ + if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + if (fll->sync_src >= 0) + arizona_apply_fll(arizona, fll->base + 0x10, sync, + fll->sync_src); + } else if (fll->sync_src >= 0) { + regmap_update_bits(arizona->regmap, fll->base + 5, + ARIZONA_FLL1_OUTDIV_MASK, + sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); + + arizona_apply_fll(arizona, fll->base, sync, fll->sync_src); + } else { + arizona_fll_err(fll, "No clocks provided\n"); + return; + } if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); @@ -1149,7 +1165,8 @@ static void arizona_enable_fll(struct arizona_fll *fll, regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); - if (fll->sync_src >= 0) + if (fll->ref_src >= 0 && fll->sync_src >= 0 && + fll->ref_src != fll->sync_src) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); @@ -1180,9 +1197,6 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (source < 0) - return -EINVAL; - if (fll->ref_src == source && fll->ref_freq == Fref) return 0; @@ -1216,39 +1230,25 @@ int arizona_set_fll(struct arizona_fll *fll, int source, struct arizona_fll_cfg ref, sync; int ret; - if (fll->ref_src < 0 || fll->ref_src == source) { - if (fll->sync_src == ARIZONA_FLL_SRC_NONE && - fll->ref_src == source && fll->ref_freq == Fref && - fll->fout == Fout) - return 0; - - if (Fout) { - ret = arizona_calc_fll(fll, &ref, Fref, Fout); - if (ret != 0) - return ret; - } - - fll->sync_src = ARIZONA_FLL_SRC_NONE; - fll->ref_src = source; - fll->ref_freq = Fref; - } else { - if (fll->sync_src == source && - fll->sync_freq == Fref && fll->fout == Fout) - return 0; - - if (Fout) { - ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout); - if (ret != 0) - return ret; + if (fll->sync_src == source && + fll->sync_freq == Fref && fll->fout == Fout) + return 0; - ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (Fout) { + if (fll->ref_src >= 0) { + ret = arizona_calc_fll(fll, &ref, fll->ref_freq, + Fout); if (ret != 0) return ret; } - fll->sync_src = source; - fll->sync_freq = Fref; + ret = arizona_calc_fll(fll, &sync, Fref, Fout); + if (ret != 0) + return ret; } + + fll->sync_src = source; + fll->sync_freq = Fref; fll->fout = Fout; if (Fout) { -- cgit v1.2.3 From e37e04307c2921ee83b192cbeb65d21897d0c6e8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Mar 2013 15:24:16 +0100 Subject: ASoC: omap3pandora: Fix compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: sound/soc/omap/omap3pandora.c: In function ‘omap3pandora_dac_event’: sound/soc/omap/omap3pandora.c:92:19: error: request for member ‘dev’ in something not a structure or union make[3]: *** [sound/soc/omap/omap3pandora.o] Error 1 Which is introduced by: dd194b4 ASoC: omap: Check regulator enable for DAC on Pandora Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap3pandora.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 10ced9d2e0de..9e46e1d8cb1b 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -89,7 +89,7 @@ static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, if (SND_SOC_DAPM_EVENT_ON(event)) { ret = regulator_enable(omap3pandora_dac_reg); if (ret) { - dev_err(w->dapm.dev, "Failed to power DAC: %d\n", ret); + dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret); return ret; } mdelay(1); -- cgit v1.2.3 From cadf2120ff756789a3adaac07c5b85a09649c66e Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Tue, 5 Mar 2013 13:12:56 -0600 Subject: ASoC: cs42l73: If Internal MCLK is >= 6.4MHz, then set SCLK to 64*Fs. Signed-off-by: Paul Handrigan Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 6361dab48bd1..3b20c86cdb01 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].mmcc &= 0xC0; priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc; priv->config[id].spc &= 0xFC; - priv->config[id].spc |= MCK_SCLK_MCLK; + /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */ + if (priv->mclk >= 6400000) + priv->config[id].spc |= MCK_SCLK_64FS; + else + priv->config[id].spc |= MCK_SCLK_MCLK; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; -- cgit v1.2.3 From 1fd9c467b4f7e08beee41f9771396f39265f4c08 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 11:51:55 +0800 Subject: mfd: arizona: Define additional FLL control registers Signed-off-by: Mark Brown --- include/linux/mfd/arizona/registers.h | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 340355136069..a61ce90ecd3f 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -85,12 +85,14 @@ #define ARIZONA_FLL1_CONTROL_6 0x176 #define ARIZONA_FLL1_LOOP_FILTER_TEST_1 0x177 #define ARIZONA_FLL1_NCO_TEST_0 0x178 +#define ARIZONA_FLL1_CONTROL_7 0x179 #define ARIZONA_FLL1_SYNCHRONISER_1 0x181 #define ARIZONA_FLL1_SYNCHRONISER_2 0x182 #define ARIZONA_FLL1_SYNCHRONISER_3 0x183 #define ARIZONA_FLL1_SYNCHRONISER_4 0x184 #define ARIZONA_FLL1_SYNCHRONISER_5 0x185 #define ARIZONA_FLL1_SYNCHRONISER_6 0x186 +#define ARIZONA_FLL1_SYNCHRONISER_7 0x187 #define ARIZONA_FLL1_SPREAD_SPECTRUM 0x189 #define ARIZONA_FLL1_GPIO_CLOCK 0x18A #define ARIZONA_FLL2_CONTROL_1 0x191 @@ -101,12 +103,14 @@ #define ARIZONA_FLL2_CONTROL_6 0x196 #define ARIZONA_FLL2_LOOP_FILTER_TEST_1 0x197 #define ARIZONA_FLL2_NCO_TEST_0 0x198 +#define ARIZONA_FLL2_CONTROL_7 0x199 #define ARIZONA_FLL2_SYNCHRONISER_1 0x1A1 #define ARIZONA_FLL2_SYNCHRONISER_2 0x1A2 #define ARIZONA_FLL2_SYNCHRONISER_3 0x1A3 #define ARIZONA_FLL2_SYNCHRONISER_4 0x1A4 #define ARIZONA_FLL2_SYNCHRONISER_5 0x1A5 #define ARIZONA_FLL2_SYNCHRONISER_6 0x1A6 +#define ARIZONA_FLL2_SYNCHRONISER_7 0x1A7 #define ARIZONA_FLL2_SPREAD_SPECTRUM 0x1A9 #define ARIZONA_FLL2_GPIO_CLOCK 0x1AA #define ARIZONA_MIC_CHARGE_PUMP_1 0x200 @@ -1677,6 +1681,13 @@ #define ARIZONA_FLL1_FRC_INTEG_VAL_SHIFT 0 /* FLL1_FRC_INTEG_VAL - [11:0] */ #define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH 12 /* FLL1_FRC_INTEG_VAL - [11:0] */ +/* + * R377 (0x179) - FLL1 Control 7 + */ +#define ARIZONA_FLL1_GAIN_MASK 0x003c /* FLL1_GAIN */ +#define ARIZONA_FLL1_GAIN_SHIFT 2 /* FLL1_GAIN */ +#define ARIZONA_FLL1_GAIN_WIDTH 4 /* FLL1_GAIN */ + /* * R385 (0x181) - FLL1 Synchroniser 1 */ @@ -1723,6 +1734,17 @@ #define ARIZONA_FLL1_CLK_SYNC_SRC_SHIFT 0 /* FLL1_CLK_SYNC_SRC - [3:0] */ #define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH 4 /* FLL1_CLK_SYNC_SRC - [3:0] */ +/* + * R391 (0x187) - FLL1 Synchroniser 7 + */ +#define ARIZONA_FLL1_SYNC_GAIN_MASK 0x003c /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_GAIN_SHIFT 2 /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_GAIN_WIDTH 4 /* FLL1_SYNC_GAIN */ +#define ARIZONA_FLL1_SYNC_BW 0x0001 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_MASK 0x0001 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_SHIFT 0 /* FLL1_SYNC_BW */ +#define ARIZONA_FLL1_SYNC_BW_WIDTH 1 /* FLL1_SYNC_BW */ + /* * R393 (0x189) - FLL1 Spread Spectrum */ @@ -1815,6 +1837,13 @@ #define ARIZONA_FLL2_FRC_INTEG_VAL_SHIFT 0 /* FLL2_FRC_INTEG_VAL - [11:0] */ #define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH 12 /* FLL2_FRC_INTEG_VAL - [11:0] */ +/* + * R409 (0x199) - FLL2 Control 7 + */ +#define ARIZONA_FLL2_GAIN_MASK 0x003c /* FLL2_GAIN */ +#define ARIZONA_FLL2_GAIN_SHIFT 2 /* FLL2_GAIN */ +#define ARIZONA_FLL2_GAIN_WIDTH 4 /* FLL2_GAIN */ + /* * R417 (0x1A1) - FLL2 Synchroniser 1 */ @@ -1861,6 +1890,17 @@ #define ARIZONA_FLL2_CLK_SYNC_SRC_SHIFT 0 /* FLL2_CLK_SYNC_SRC - [3:0] */ #define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH 4 /* FLL2_CLK_SYNC_SRC - [3:0] */ +/* + * R423 (0x1A7) - FLL2 Synchroniser 7 + */ +#define ARIZONA_FLL2_SYNC_GAIN_MASK 0x003c /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_GAIN_SHIFT 2 /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_GAIN_WIDTH 4 /* FLL2_SYNC_GAIN */ +#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_SHIFT 0 /* FLL2_SYNC_BW */ +#define ARIZONA_FLL2_SYNC_BW_WIDTH 1 /* FLL2_SYNC_BW */ + /* * R425 (0x1A9) - FLL2 Spread Spectrum */ -- cgit v1.2.3 From 9a412cdb1ab0ad984b76debfe562cb7a2c815371 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 11:53:09 +0800 Subject: mfd: wm5102: Map in additional FLL control registers Signed-off-by: Mark Brown --- drivers/mfd/wm5102-tables.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index a433f580aa4c..8a6ce8c12505 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ { 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ @@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ @@ -1051,12 +1055,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_CONTROL_6: case ARIZONA_FLL1_LOOP_FILTER_TEST_1: case ARIZONA_FLL1_NCO_TEST_0: + case ARIZONA_FLL1_CONTROL_7: case ARIZONA_FLL1_SYNCHRONISER_1: case ARIZONA_FLL1_SYNCHRONISER_2: case ARIZONA_FLL1_SYNCHRONISER_3: case ARIZONA_FLL1_SYNCHRONISER_4: case ARIZONA_FLL1_SYNCHRONISER_5: case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: case ARIZONA_FLL1_SPREAD_SPECTRUM: case ARIZONA_FLL1_GPIO_CLOCK: case ARIZONA_FLL2_CONTROL_1: @@ -1067,12 +1073,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_CONTROL_6: case ARIZONA_FLL2_LOOP_FILTER_TEST_1: case ARIZONA_FLL2_NCO_TEST_0: + case ARIZONA_FLL2_CONTROL_7: case ARIZONA_FLL2_SYNCHRONISER_1: case ARIZONA_FLL2_SYNCHRONISER_2: case ARIZONA_FLL2_SYNCHRONISER_3: case ARIZONA_FLL2_SYNCHRONISER_4: case ARIZONA_FLL2_SYNCHRONISER_5: case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: case ARIZONA_FLL2_SPREAD_SPECTRUM: case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: -- cgit v1.2.3 From 576411be200ee0e0801f1fe57d5e7ee787bb1a90 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 12:07:16 +0800 Subject: ASoC: arizona: Increase FLL synchroniser bandwidth for high frequencies If we are using a high freqency SYNCCLK then increasing the bandwidth of the synchroniser improves performance. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0599ff8ea935..e3aee143487e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1157,6 +1157,17 @@ static void arizona_enable_fll(struct arizona_fll *fll, return; } + /* + * Increase the bandwidth if we're not using a low frequency + * sync source. + */ + if (fll->sync_src >= 0 && fll->sync_freq > 100000) + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, 0); + else + regmap_update_bits(arizona->regmap, fll->base + 0x17, + ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); + if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); -- cgit v1.2.3 From 8f113d7d2606003e485c4e8452977750d916dbc6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 12:08:57 +0800 Subject: ASoC: arizona: Optimise FLL loop gains For optimal performance the FLL loop gain should be adjusted depending on the frequency of the input clock for the loop. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e3aee143487e..8b7855df99de 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -990,6 +990,16 @@ static struct { { 1000000, 13500000, 0, 1 }, }; +static struct { + unsigned int min; + unsigned int max; + u16 gain; +} fll_gains[] = { + { 0, 256000, 0 }, + { 256000, 1000000, 2 }, + { 1000000, 13500000, 4 }, +}; + struct arizona_fll_cfg { int n; int theta; @@ -997,6 +1007,7 @@ struct arizona_fll_cfg { int refdiv; int outdiv; int fratio; + int gain; }; static int arizona_calc_fll(struct arizona_fll *fll, @@ -1056,6 +1067,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, return -EINVAL; } + for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { + if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { + cfg->gain = fll_gains[i].gain; + break; + } + } + if (i == ARRAY_SIZE(fll_gains)) { + arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", + Fref); + return -EINVAL; + } + cfg->n = target / (ratio * Fref); if (target % (ratio * Fref)) { @@ -1083,13 +1106,15 @@ static int arizona_calc_fll(struct arizona_fll *fll, cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); + arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain); return 0; } static void arizona_apply_fll(struct arizona *arizona, unsigned int base, - struct arizona_fll_cfg *cfg, int source) + struct arizona_fll_cfg *cfg, int source, + bool sync) { regmap_update_bits(arizona->regmap, base + 3, ARIZONA_FLL1_THETA_MASK, cfg->theta); @@ -1104,6 +1129,15 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); + if (sync) + regmap_update_bits(arizona->regmap, base + 0x7, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + else + regmap_update_bits(arizona->regmap, base + 0x9, + ARIZONA_FLL1_GAIN_MASK, + cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); + regmap_update_bits(arizona->regmap, base + 2, ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, ARIZONA_FLL1_CTRL_UPD | cfg->n); @@ -1141,17 +1175,18 @@ static void arizona_enable_fll(struct arizona_fll *fll, ARIZONA_FLL1_OUTDIV_MASK, ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); - arizona_apply_fll(arizona, fll->base, ref, fll->ref_src); + arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, + false); if (fll->sync_src >= 0) arizona_apply_fll(arizona, fll->base + 0x10, sync, - fll->sync_src); + fll->sync_src, true); } else if (fll->sync_src >= 0) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, sync, - fll->sync_src); + fll->sync_src, false); } else { arizona_fll_err(fll, "No clocks provided\n"); return; -- cgit v1.2.3 From 27a737ff7cb062fb9cbceba9b44d60aa74862bfa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Mar 2013 23:17:08 +0100 Subject: mac80211: always synchronize_net() during station removal If there are keys left during station removal, then a synchronize_net() will be done (for each key, I have a patch to address this for 3.10), otherwise it won't be done at all which causes issues because the station could be used for TX while it's being removed from the driver -- that might confuse the driver. Fix this by always doing synchronize_net() if no key was present any more. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a79ce820cb50..238a0cca320e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -766,6 +766,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; int ret, i; + bool have_key = false; might_sleep(); @@ -793,12 +794,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta) list_del_rcu(&sta->list); mutex_lock(&local->key_mtx); - for (i = 0; i < NUM_DEFAULT_KEYS; i++) + for (i = 0; i < NUM_DEFAULT_KEYS; i++) { __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); - if (sta->ptk) + have_key = true; + } + if (sta->ptk) { __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); + have_key = true; + } mutex_unlock(&local->key_mtx); + if (!have_key) + synchronize_net(); + sta->dead = true; local->num_sta--; -- cgit v1.2.3 From b0ec761b99291f3c0f28ac370f94c145ec806095 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 6 Mar 2013 22:22:15 +0100 Subject: ASoC: ak4104: convert to direct regmap API usage Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/ak4104.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 6f6c335a5baa..58f390d3ea7a 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int val = 0; int ret; @@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; - ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, - val); + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, + AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, + val); if (ret < 0) return ret; @@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); int val = 0; /* set the IEC958 bits: consumer mode, no copyright bit */ val |= IEC958_AES0_CON_NOT_COPYRIGHT; - snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val); + regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val); val = 0; @@ -132,7 +134,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val); + return regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val); } static const struct snd_soc_dai_ops ak4101_dai_ops = { @@ -160,20 +162,17 @@ static int ak4104_probe(struct snd_soc_codec *codec) int ret; codec->control_data = ak4104->regmap; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); - if (ret != 0) - return ret; /* set power-up and non-reset bits */ - ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0) return ret; /* enable transmitter */ - ret = snd_soc_update_bits(codec, AK4104_REG_TX, - AK4104_TX_TXE, AK4104_TX_TXE); + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) return ret; @@ -182,8 +181,10 @@ static int ak4104_probe(struct snd_soc_codec *codec) static int ak4104_remove(struct snd_soc_codec *codec) { - snd_soc_update_bits(codec, AK4104_REG_CONTROL1, - AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); return 0; } -- cgit v1.2.3 From b692a436e1dc7227f2b7cf447797c3dc6ece5c29 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 6 Mar 2013 22:22:16 +0100 Subject: ASoC: ak4104: correct tranceiver enable handling Move the enabling of the TX diode to hw_params() and disable it again in hw_free(). This way, the diode is only switched on as long as it needs to be. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/ak4104.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 58f390d3ea7a..c7cfdf957e4d 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -93,7 +93,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); - int val = 0; + int ret, val = 0; /* set the IEC958 bits: consumer mode, no copyright bit */ val |= IEC958_AES0_CON_NOT_COPYRIGHT; @@ -134,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val); + ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val); + if (ret < 0) + return ret; + + /* enable transmitter */ + ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, AK4104_TX_TXE); + if (ret < 0) + return ret; + + return 0; +} + +static int ak4104_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); + + /* disable transmitter */ + return regmap_update_bits(ak4104->regmap, AK4104_REG_TX, + AK4104_TX_TXE, 0); } static const struct snd_soc_dai_ops ak4101_dai_ops = { .hw_params = ak4104_hw_params, + .hw_free = ak4104_hw_free, .set_fmt = ak4104_set_dai_fmt, }; -- cgit v1.2.3 From ad4e1a7caf937ad395ced585ca85a7d14395dc80 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Sun, 17 Feb 2013 19:42:48 +0800 Subject: gpio: fix wrong checking condition for gpio range If index++ calculates from 0, the checking condition of "while (index++)" fails & it doesn't check any more. It doesn't follow the loop that used at here. Replace it by endless loop at here. Then it keeps parsing "gpio-ranges" property until it ends. Signed-off-by: Haojian Zhuang Reviewed-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a71a54a3e3f7..5150df6cba08 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -193,7 +193,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!np) return; - do { + for (;; index++) { ret = of_parse_phandle_with_args(np, "gpio-ranges", "#gpio-range-cells", index, &pinspec); if (ret) @@ -222,8 +222,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (ret) break; - - } while (index++); + } } #else -- cgit v1.2.3 From 021fcdc13acbab78589325ae2db0b384b4ee7222 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 7 Mar 2013 11:08:29 +0200 Subject: cfg80211: fix inconsistency in trace for rdev_set_mac_acl There is NETDEV_ENTRY that was incorrectly assigned as WIPHY_ASSIGN, fix it. Signed-off-by: Vladimir Kondratiev Signed-off-by: Johannes Berg --- net/wireless/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index b7a531380e19..6847d043edea 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1778,7 +1778,7 @@ TRACE_EVENT(rdev_set_mac_acl, ), TP_fast_assign( WIPHY_ASSIGN; - WIPHY_ASSIGN; + NETDEV_ASSIGN; __entry->acl_policy = params->acl_policy; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d", -- cgit v1.2.3 From 1345ee6a6d90813f972379fad8b75f17026fc8b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Mar 2013 10:31:05 +0100 Subject: cfg80211: fix potential BSS memory leak and update In the odd case that while updating information from a beacon, a BSS was found that is part of a hidden group, we drop the new information. In this case, however, we leak the IE buffer from the update, and erroneously update the entry's timestamp so it will never time out. Fix both these issues. Cc: Larry Finger Signed-off-by: Johannes Berg --- net/wireless/scan.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 674aadca0079..e93bd31d23bb 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR); if (found) { - found->pub.beacon_interval = tmp->pub.beacon_interval; - found->pub.signal = tmp->pub.signal; - found->pub.capability = tmp->pub.capability; - found->ts = tmp->ts; - /* Update IEs */ if (rcu_access_pointer(tmp->pub.proberesp_ies)) { const struct cfg80211_bss_ies *old; @@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, if (found->pub.hidden_beacon_bss && !list_empty(&found->hidden_list)) { + const struct cfg80211_bss_ies *f; + /* * The found BSS struct is one of the probe * response members of a group, but we're @@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, * SSID to showing it, which is confusing so * drop this information. */ + + f = rcu_access_pointer(tmp->pub.beacon_ies); + kfree_rcu((struct cfg80211_bss_ies *)f, + rcu_head); goto drop; } @@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); } + + found->pub.beacon_interval = tmp->pub.beacon_interval; + found->pub.signal = tmp->pub.signal; + found->pub.capability = tmp->pub.capability; + found->ts = tmp->ts; } else { struct cfg80211_internal_bss *new; struct cfg80211_internal_bss *hidden; -- cgit v1.2.3 From a7dc19b8652c862d5b7c4d2339bd3c428bd29c4a Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 7 Mar 2013 15:09:24 +0000 Subject: clockevents: Don't allow dummy broadcast timers Currently tick_check_broadcast_device doesn't reject clock_event_devices with CLOCK_EVT_FEAT_DUMMY, and may select them in preference to real hardware if they have a higher rating value. In this situation, the dummy timer is responsible for broadcasting to itself, and the core clockevents code may attempt to call non-existent callbacks for programming the dummy, eventually leading to a panic. This patch makes tick_check_broadcast_device always reject dummy timers, preventing this problem. Signed-off-by: Mark Rutland Cc: linux-arm-kernel@lists.infradead.org Cc: Jon Medhurst (Tixy) Cc: stable@vger.kernel.org Signed-off-by: Thomas Gleixner --- kernel/time/tick-broadcast.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 2fb8cb88df8d..7f32fe0e52cd 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -67,7 +67,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) */ int tick_check_broadcast_device(struct clock_event_device *dev) { - if ((tick_broadcast_device.evtdev && + if ((dev->features & CLOCK_EVT_FEAT_DUMMY) || + (tick_broadcast_device.evtdev && tick_broadcast_device.evtdev->rating >= dev->rating) || (dev->features & CLOCK_EVT_FEAT_C3STOP)) return 0; -- cgit v1.2.3 From eca2e8e24a0c712c2613ce5704e9e73b693d2e98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Mar 2013 00:09:59 +0800 Subject: ASoC: arizona: Ensure synchroniser is disabled when not needed When live configuring a FLL configuration with no synchroniser disable the synchroniser in case the previous configuration used one. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 8b7855df99de..53ddd529769c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1187,6 +1187,9 @@ static void arizona_enable_fll(struct arizona_fll *fll, arizona_apply_fll(arizona, fll->base, sync, fll->sync_src, false); + + regmap_update_bits(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0); } else { arizona_fll_err(fll, "No clocks provided\n"); return; -- cgit v1.2.3 From 86cd684fcb3220f4aa20cf9e32fd1059373a608a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 7 Mar 2013 16:14:04 +0800 Subject: ASoC: arizona: Suppress reference calculations when setting REFCLK to 0 Allow users to keep on specifying their output frequency when disabling the reference clock. Reported-by: Kyung Kwee Ryu Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 53ddd529769c..ad21d8255341 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1249,7 +1249,7 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, if (fll->ref_src == source && fll->ref_freq == Fref) return 0; - if (fll->fout) { + if (fll->fout && Fref > 0) { ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); if (ret != 0) return ret; @@ -1265,7 +1265,7 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_src = source; fll->ref_freq = Fref; - if (fll->fout) { + if (fll->fout && Fref > 0) { arizona_enable_fll(fll, &ref, &sync); } -- cgit v1.2.3 From cc289be8c913006a43275dfd8ed4ac56b43140a8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 8 Mar 2013 12:07:28 +0100 Subject: ASoC: Add codec driver for AK5386 Adds a driver for Asahi Kasei's AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC. The device has no control port interface but an optional RESET/PDN GPIO pin. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak5386.txt | 19 +++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ak5386.c | 152 +++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ak5386.txt create mode 100644 sound/soc/codecs/ak5386.c diff --git a/Documentation/devicetree/bindings/sound/ak5386.txt b/Documentation/devicetree/bindings/sound/ak5386.txt new file mode 100644 index 000000000000..dc3914fe6ce8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ak5386.txt @@ -0,0 +1,19 @@ +AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC + +This device has no control interface. + +Required properties: + + - compatible : "asahi-kasei,ak5386" + +Optional properties: + + - reset-gpio : a GPIO spec for the reset/power down pin. + If specified, it will be deasserted at probe time. + +Example: + +spdif: ak5386@0 { + compatible = "asahi-kasei,ak5386"; + reset-gpio = <&gpio0 23>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 45b72561c615..500f666c3875 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4641 if I2C select SND_SOC_AK4642 if I2C select SND_SOC_AK4671 if I2C + select SND_SOC_AK5386 select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC @@ -203,6 +204,9 @@ config SND_SOC_AK4642 config SND_SOC_AK4671 tristate +config SND_SOC_AK5386 + tristate + config SND_SOC_ALC5623 tristate config SND_SOC_ALC5632 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6a3b3c3b8b41..3a7ec1c39741 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -14,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o snd-soc-ak4641-objs := ak4641.o snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o +snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs42l51-objs := cs42l51.o @@ -137,6 +138,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o +obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c new file mode 100644 index 000000000000..1f303983ae02 --- /dev/null +++ b/sound/soc/codecs/ak5386.c @@ -0,0 +1,152 @@ +/* + * ALSA SoC driver for + * Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC + * + * (c) 2013 Daniel Mack + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +struct ak5386_priv { + int reset_gpio; +}; + +static struct snd_soc_codec_driver soc_codec_ak5386; + +static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + format &= SND_SOC_DAIFMT_FORMAT_MASK; + if (format != SND_SOC_DAIFMT_LEFT_J && + format != SND_SOC_DAIFMT_I2S) { + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static int ak5386_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + + /* + * From the datasheet: + * + * All external clocks (MCLK, SCLK and LRCK) must be present unless + * PDN pin = “L”. If these clocks are not provided, the AK5386 may + * draw excess current due to its use of internal dynamically + * refreshed logic. If the external clocks are not present, place + * the AK5386 in power-down mode (PDN pin = “L”). + */ + + if (gpio_is_valid(priv->reset_gpio)) + gpio_set_value(priv->reset_gpio, 1); + + return 0; +} + +static int ak5386_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(priv->reset_gpio)) + gpio_set_value(priv->reset_gpio, 0); + + return 0; +} + +static const struct snd_soc_dai_ops ak5386_dai_ops = { + .set_fmt = ak5386_set_dai_fmt, + .hw_params = ak5386_hw_params, + .hw_free = ak5386_hw_free, +}; + +static struct snd_soc_dai_driver ak5386_dai = { + .name = "ak5386-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE, + }, + .ops = &ak5386_dai_ops, +}; + +#ifdef CONFIG_OF +static const struct of_device_id ak5386_dt_ids[] = { + { .compatible = "asahi-kasei,ak5386", }, + { } +}; +MODULE_DEVICE_TABLE(of, ak5386_dt_ids); +#endif + +static int ak5386_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ak5386_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reset_gpio = -EINVAL; + dev_set_drvdata(dev, priv); + + if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) + priv->reset_gpio = of_get_named_gpio(dev->of_node, + "reset-gpio", 0); + + if (gpio_is_valid(priv->reset_gpio)) + if (devm_gpio_request_one(dev, priv->reset_gpio, + GPIOF_OUT_INIT_LOW, + "AK5386 Reset")) + priv->reset_gpio = -EINVAL; + + return snd_soc_register_codec(dev, &soc_codec_ak5386, + &ak5386_dai, 1); +} + +static int ak5386_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver ak5386_driver = { + .probe = ak5386_probe, + .remove = ak5386_remove, + .driver = { + .name = "ak5386", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ak5386_dt_ids), + }, +}; + +module_platform_driver(ak5386_driver); + +MODULE_DESCRIPTION("ASoC driver for AK5386 ADC"); +MODULE_AUTHOR("Daniel Mack "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e383c467ceeee3b040444d6dcd27f331d72b1426 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 8 Mar 2013 13:44:26 +0100 Subject: ASoC: core: Drop unused "dapm" field form soc_enum struct This field was added in commit 2e72f8e ("ASoC: New enum type: value_enum"), but has never been used since. Considering that the soc_enum struct is usually shared between all instances of a CODEC, it also doesn't make much sense to have a pointer to DAPM specific data in it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index a6a059ca3874..c84062b22221 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1086,7 +1086,6 @@ struct soc_enum { unsigned int mask; const char * const *texts; const unsigned int *values; - void *dapm; }; /* codec IO */ -- cgit v1.2.3 From a93f8e76a446e0a146a169cc2cc82bf1e145ad35 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 8 Mar 2013 13:44:27 +0100 Subject: ASoC: core: Remove unused "n_widgets" field from snd_soc_dapm struct Commit 497098be ("ASoC: dapm: Remove bodges for no-widget CODECs") removed the last user of the n_widgets field. Currently it is incremented for each widget added, but the value is never used, so we can remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 - sound/soc/soc-dapm.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e1ef63d4a5c4..d4c004929ae5 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -565,7 +565,6 @@ struct snd_soc_dapm_update { /* DAPM context */ struct snd_soc_dapm_context { - int n_widgets; /* number of widgets in this context */ enum snd_soc_bias_level bias_level; enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1d6a9b3ceb27..625d4824abbb 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3123,7 +3123,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, break; } - dapm->n_widgets++; w->dapm = dapm; w->codec = dapm->codec; w->platform = dapm->platform; -- cgit v1.2.3 From 4fa89346fbc34750f96ec0c1b2b59b15596ab333 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 8 Mar 2013 13:52:09 +0100 Subject: ALSA: ASoC: add codec driver for TI TAS5086 This patch adds a driver for TI's TA5086 6-channel PWM processor. This chip has a very unusual register layout, specifically because the registers are of unequal size, and multi-byte registers require bulk writes to take effect. Regmap does not support these kind of mappings. Currently, the driver does not touch any of the registers >= 0x20, so it doesn't matter, because the register map is mapped to an 8-bit array. In case more features will be added in the future that require access to higher registers, the entire regmap H/W I/O routines have to be open-coded. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,tas5086.txt | 32 ++ include/sound/tas5086.h | 7 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas5086.c | 601 +++++++++++++++++++++ 5 files changed, 646 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tas5086.txt create mode 100644 include/sound/tas5086.h create mode 100644 sound/soc/codecs/tas5086.c diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt new file mode 100644 index 000000000000..8ea4f5b4818d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas5086.txt @@ -0,0 +1,32 @@ +Texas Instruments TAS5086 6-channel PWM Processor + +Required properties: + + - compatible: Should contain "ti,tas5086". + - reg: The i2c address. Should contain <0x1b>. + +Optional properties: + + - reset-gpio: A GPIO spec to define which pin is connected to the + chip's !RESET pin. If specified, the driver will + assert a hardware reset at probe time. + + - ti,charge-period: This property should contain the time in microseconds + that closely matches the external single-ended + split-capacitor charge period. The hardware chip + waits for this period of time before starting the + PWM signals. This helps reduce pops and clicks. + + When not specified, the hardware default of 1300ms + is retained. + +Examples: + + i2c_bus { + tas5086@1b { + compatible = "ti,tas5086"; + reg = <0x1b>; + reset-gpio = <&gpio 23 0>; + ti,charge-period = <156000>; + }; + }; diff --git a/include/sound/tas5086.h b/include/sound/tas5086.h new file mode 100644 index 000000000000..aac481b7db8f --- /dev/null +++ b/include/sound/tas5086.h @@ -0,0 +1,7 @@ +#ifndef _SND_SOC_CODEC_TAS5086_H_ +#define _SND_SOC_CODEC_TAS5086_H_ + +#define TAS5086_CLK_IDX_MCLK 0 +#define TAS5086_CLK_IDX_SCLK 1 + +#endif /* _SND_SOC_CODEC_TAS5086_H_ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 45b72561c615..86b35245e559 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -63,6 +63,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA32X if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_TAS5086 if I2C select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC32X4 if I2C @@ -320,6 +321,9 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate +config SND_SOC_TAS5086 + tristate + config SND_SOC_TLV320AIC23 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6a3b3c3b8b41..8077bc2b4f43 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-sta32x-objs := sta32x.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o +snd-soc-tas5086-objs := tas5086.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o @@ -177,6 +178,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c new file mode 100644 index 000000000000..008bea4d6208 --- /dev/null +++ b/sound/soc/codecs/tas5086.c @@ -0,0 +1,601 @@ +/* + * TAS5086 ASoC codec driver + * + * Copyright (c) 2013 Daniel Mack + * + * 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. + * + * TODO: + * - implement DAPM and input muxing + * - implement modulation limit + * - implement non-default PWM start + * + * Note that this chip has a very unusual register layout, specifically + * because the registers are of unequal size, and multi-byte registers + * require bulk writes to take effect. Regmap does not support that kind + * of devices. + * + * Currently, the driver does not touch any of the registers >= 0x20, so + * it doesn't matter because the entire map can be accessed as 8-bit + * array. In case more features will be added in the future + * that require access to higher registers, the entire regmap H/W I/O + * routines have to be open-coded. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TAS5086_PCM_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +/* + * TAS5086 registers + */ +#define TAS5086_CLOCK_CONTROL 0x00 /* Clock control register */ +#define TAS5086_CLOCK_RATE(val) (val << 5) +#define TAS5086_CLOCK_RATE_MASK (0x7 << 5) +#define TAS5086_CLOCK_RATIO(val) (val << 2) +#define TAS5086_CLOCK_RATIO_MASK (0x7 << 2) +#define TAS5086_CLOCK_SCLK_RATIO_48 (1 << 1) +#define TAS5086_CLOCK_VALID (1 << 0) + +#define TAS5086_DEEMPH_MASK 0x03 +#define TAS5086_SOFT_MUTE_ALL 0x3f + +#define TAS5086_DEV_ID 0x01 /* Device ID register */ +#define TAS5086_ERROR_STATUS 0x02 /* Error status register */ +#define TAS5086_SYS_CONTROL_1 0x03 /* System control register 1 */ +#define TAS5086_SERIAL_DATA_IF 0x04 /* Serial data interface register */ +#define TAS5086_SYS_CONTROL_2 0x05 /* System control register 2 */ +#define TAS5086_SOFT_MUTE 0x06 /* Soft mute register */ +#define TAS5086_MASTER_VOL 0x07 /* Master volume */ +#define TAS5086_CHANNEL_VOL(X) (0x08 + (X)) /* Channel 1-6 volume */ +#define TAS5086_VOLUME_CONTROL 0x09 /* Volume control register */ +#define TAS5086_MOD_LIMIT 0x10 /* Modulation limit register */ +#define TAS5086_PWM_START 0x18 /* PWM start register */ +#define TAS5086_SURROUND 0x19 /* Surround register */ +#define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ +#define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ +#define TAS5086_BKNDERR 0x1c + +/* + * Default TAS5086 power-up configuration + */ +static const struct reg_default tas5086_reg_defaults[] = { + { 0x00, 0x6c }, + { 0x01, 0x03 }, + { 0x02, 0x00 }, + { 0x03, 0xa0 }, + { 0x04, 0x05 }, + { 0x05, 0x60 }, + { 0x06, 0x00 }, + { 0x07, 0xff }, + { 0x08, 0x30 }, + { 0x09, 0x30 }, + { 0x0a, 0x30 }, + { 0x0b, 0x30 }, + { 0x0c, 0x30 }, + { 0x0d, 0x30 }, + { 0x0e, 0xb1 }, + { 0x0f, 0x00 }, + { 0x10, 0x02 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x15, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, + { 0x18, 0x3f }, + { 0x19, 0x00 }, + { 0x1a, 0x18 }, + { 0x1b, 0x82 }, + { 0x1c, 0x05 }, +}; + +static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) +{ + return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); +} + +static bool tas5086_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS5086_DEV_ID: + case TAS5086_ERROR_STATUS: + return true; + } + + return false; +} + +static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) +{ + return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); +} + +struct tas5086_private { + struct regmap *regmap; + unsigned int mclk, sclk; + unsigned int format; + bool deemph; + /* Current sample rate for de-emphasis control */ + int rate; + /* GPIO driving Reset pin, if any */ + int gpio_nreset; +}; + +static int tas5086_deemph[] = { 0, 32000, 44100, 48000 }; + +static int tas5086_set_deemph(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int i, val = 0; + + if (priv->deemph) + for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) + if (tas5086_deemph[i] == priv->rate) + val = i; + + return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1, + TAS5086_DEEMPH_MASK, val); +} + +static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = priv->deemph; + + return 0; +} + +static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + priv->deemph = ucontrol->value.enumerated.item[0]; + + return tas5086_set_deemph(codec); +} + + +static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case TAS5086_CLK_IDX_MCLK: + priv->mclk = freq; + break; + case TAS5086_CLK_IDX_SCLK: + priv->sclk = freq; + break; + } + + return 0; +} + +static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + /* The TAS5086 can only be slave to all clocks */ + if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Invalid clocking mode\n"); + return -EINVAL; + } + + /* we need to refer to the data format from hw_params() */ + priv->format = format; + + return 0; +} + +static const int tas5086_sample_rates[] = { + 32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const int tas5086_ratios[] = { + 64, 128, 192, 256, 384, 512 +}; + +static int index_in_array(const int *array, int len, int needle) +{ + int i; + + for (i = 0; i < len; i++) + if (array[i] == needle) + return i; + + return -ENOENT; +} + +static int tas5086_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int ret; + + priv->rate = params_rate(params); + + /* Look up the sample rate and refer to the offset in the list */ + val = index_in_array(tas5086_sample_rates, + ARRAY_SIZE(tas5086_sample_rates), priv->rate); + + if (val < 0) { + dev_err(codec->dev, "Invalid sample rate\n"); + return -EINVAL; + } + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_RATE_MASK, + TAS5086_CLOCK_RATE(val)); + if (ret < 0) + return ret; + + /* MCLK / Fs ratio */ + val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios), + priv->mclk / priv->rate); + if (val < 0) { + dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n"); + return -EINVAL; + } + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_RATIO_MASK, + TAS5086_CLOCK_RATIO(val)); + if (ret < 0) + return ret; + + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_SCLK_RATIO_48, + (priv->sclk == 48 * priv->rate) ? + TAS5086_CLOCK_SCLK_RATIO_48 : 0); + if (ret < 0) + return ret; + + /* + * The chip has a very unituitive register mapping and muxes information + * about data format and sample depth into the same register, but not on + * a logical bit-boundary. Hence, we have to refer to the format passed + * in the set_dai_fmt() callback and set up everything from here. + * + * First, determine the 'base' value, using the format ... + */ + switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + val = 0x00; + break; + case SND_SOC_DAIFMT_I2S: + val = 0x03; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = 0x06; + break; + default: + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + /* ... then add the offset for the sample bit depth. */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val += 0; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val += 1; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + val += 2; + break; + default: + dev_err(codec->dev, "Invalid bit width\n"); + return -EINVAL; + }; + + ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val); + if (ret < 0) + return ret; + + /* clock is considered valid now */ + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID); + if (ret < 0) + return ret; + + return tas5086_set_deemph(codec); +} + +static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + + if (mute) + val = TAS5086_SOFT_MUTE_ALL; + + return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); +} + +/* TAS5086 controls */ +static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); + +static const struct snd_kcontrol_new tas5086_controls[] = { + SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL, + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", + TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", + TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", + TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, + tas5086_get_deemph, tas5086_put_deemph), +}; + +static const struct snd_soc_dai_ops tas5086_dai_ops = { + .hw_params = tas5086_hw_params, + .set_sysclk = tas5086_set_dai_sysclk, + .set_fmt = tas5086_set_dai_fmt, + .mute_stream = tas5086_mute_stream, +}; + +static struct snd_soc_dai_driver tas5086_dai = { + .name = "tas5086-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 6, + .rates = TAS5086_PCM_RATES, + .formats = TAS5086_PCM_FORMATS, + }, + .ops = &tas5086_dai_ops, +}; + +#ifdef CONFIG_PM +static int tas5086_soc_resume(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + /* Restore codec state */ + return regcache_sync(priv->regmap); +} +#else +#define tas5086_soc_resume NULL +#endif /* CONFIG_PM */ + +#ifdef CONFIG_OF +static const struct of_device_id tas5086_dt_ids[] = { + { .compatible = "ti,tas5086", }, + { } +}; +MODULE_DEVICE_TABLE(of, tas5086_dt_ids); +#endif + +/* charge period values in microseconds */ +static const int tas5086_charge_period[] = { + 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, + 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, + 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, +}; + +static int tas5086_probe(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int charge_period = 1300000; /* hardware default is 1300 ms */ + int i, ret; + + if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { + struct device_node *of_node = codec->dev->of_node; + of_property_read_u32(of_node, "ti,charge-period", &charge_period); + } + + /* lookup and set split-capacitor charge period */ + if (charge_period == 0) { + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); + } else { + i = index_in_array(tas5086_charge_period, + ARRAY_SIZE(tas5086_charge_period), + charge_period); + if (i >= 0) + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, + i + 0x08); + else + dev_warn(codec->dev, + "Invalid split-cap charge period of %d ns.\n", + charge_period); + } + + /* enable factory trim */ + ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); + if (ret < 0) + return ret; + + /* start all channels */ + ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); + if (ret < 0) + return ret; + + /* set master volume to 0 dB */ + ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30); + if (ret < 0) + return ret; + + /* mute all channels for now */ + ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, + TAS5086_SOFT_MUTE_ALL); + if (ret < 0) + return ret; + + return 0; +} + +static int tas5086_remove(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(priv->gpio_nreset)) + /* Set codec to the reset state */ + gpio_set_value(priv->gpio_nreset, 0); + + return 0; +}; + +static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { + .probe = tas5086_probe, + .remove = tas5086_remove, + .resume = tas5086_soc_resume, + .controls = tas5086_controls, + .num_controls = ARRAY_SIZE(tas5086_controls), +}; + +static const struct i2c_device_id tas5086_i2c_id[] = { + { "tas5086", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id); + +static const struct regmap_config tas5086_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ARRAY_SIZE(tas5086_reg_defaults), + .reg_defaults = tas5086_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = tas5086_volatile_reg, + .writeable_reg = tas5086_writeable_reg, + .readable_reg = tas5086_accessible_reg, +}; + +static int tas5086_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct tas5086_private *priv; + struct device *dev = &i2c->dev; + int gpio_nreset = -EINVAL; + int i, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) { + struct device_node *of_node = dev->of_node; + gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0); + } + + if (gpio_is_valid(gpio_nreset)) + if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) + gpio_nreset = -EINVAL; + + if (gpio_is_valid(gpio_nreset)) { + /* Reset codec - minimum assertion time is 400ns */ + gpio_direction_output(gpio_nreset, 0); + udelay(1); + gpio_set_value(gpio_nreset, 1); + + /* Codec needs ~15ms to wake up */ + msleep(15); + } + + priv->gpio_nreset = gpio_nreset; + + /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ + ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); + if (ret < 0) + return ret; + + if (i != 0x3) { + dev_err(dev, + "Failed to identify TAS5086 codec (got %02x)\n", i); + return -ENODEV; + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086, + &tas5086_dai, 1); +} + +static int tas5086_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static struct i2c_driver tas5086_i2c_driver = { + .driver = { + .name = "tas5086", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tas5086_dt_ids), + }, + .id_table = tas5086_i2c_id, + .probe = tas5086_i2c_probe, + .remove = tas5086_i2c_remove, +}; + +static int __init tas5086_modinit(void) +{ + return i2c_add_driver(&tas5086_i2c_driver); +} +module_init(tas5086_modinit); + +static void __exit tas5086_modexit(void) +{ + i2c_del_driver(&tas5086_i2c_driver); +} +module_exit(tas5086_modexit); + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6659a20a76e0213ad84c33ad35024278811ed010 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 7 Mar 2013 13:50:16 +0530 Subject: ARC: MAINTAINERS update for ARC * Remove the non-functional mailing list placeholder * Add entries for arc_uart/Documentation Signed-off-by: Vineet Gupta --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e95b1e944eb7..8e2ced44bfe4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7696,9 +7696,10 @@ F: include/linux/swiotlb.h SYNOPSYS ARC ARCHITECTURE M: Vineet Gupta -L: linux-snps-arc@vger.kernel.org S: Supported F: arch/arc/ +F: Documentation/devicetree/bindings/arc/ +F: drivers/tty/serial/arc-uart.c SYSV FILESYSTEM M: Christoph Hellwig -- cgit v1.2.3 From e2f1a3bd8cdc046ece133a9e9ee6bd94727225b1 Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Tue, 26 Feb 2013 16:12:05 +0100 Subject: amd_iommu_init: remove __init from amd_iommu_erratum_746_workaround commit 318fe78 ("IOMMU, AMD Family15h Model10-1Fh erratum 746 Workaround") added amd_iommu_erratum_746_workaround and it's marked as __init, which is wrong WARNING: drivers/iommu/built-in.o(.text+0x639c): Section mismatch in reference from the function iommu_init_pci() to the function .init.text:amd_iommu_erratum_746_workaround() The function iommu_init_pci() references the function __init amd_iommu_erratum_746_workaround(). This is often because iommu_init_pci lacks a __init annotation or the annotation of amd_iommu_erratum_746_workaround is wrong. Signed-off-by: Nikola Pajkovsky Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b6ecddb63cd0..e3c2d74b7684 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -980,7 +980,7 @@ static void __init free_iommu_all(void) * BIOS should disable L2B micellaneous clock gating by setting * L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b */ -static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) +static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) { u32 value; -- cgit v1.2.3 From ae1915892b4774655a5dc01039ce94efdff4b3fc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 5 Mar 2013 23:16:48 +0100 Subject: iommu: OMAP: build only on OMAP2+ The OMAP IOMMU driver intentionally fails to build on OMAP1 platforms, so we should not allow enabling it there. Signed-off-by: Arnd Bergmann Cc: Joerg Roedel Cc: iommu@lists.linux-foundation.org Cc: Ohad Ben-Cohen Cc: Tony Lindgren Cc: Omar Ramirez Luna Acked-by: Tony Lindgren Signed-off-by: Joerg Roedel --- drivers/iommu/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 5c514d0711d1..c332fb98480d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -130,7 +130,7 @@ config IRQ_REMAP # OMAP IOMMU support config OMAP_IOMMU bool "OMAP IOMMU Support" - depends on ARCH_OMAP + depends on ARCH_OMAP2PLUS select IOMMU_API config OMAP_IOVMM -- cgit v1.2.3 From 07e5a5f5ab7474589c15fc5d88e4f7fc43979530 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Mar 2013 13:22:05 +0100 Subject: mac80211: fix crash with P2P Device returning action frames If a P2P Device interface receives an unhandled action frame, we attempt to return it. This crashes because it doesn't have a channel context. Fix the crash by using status->band and properly mark the return frame as an off-channel frame. Reported-by: Ilan Peer Reviewed-by: Ilan Peer Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bb73ed2d20b9..c6844ad080be 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2675,7 +2675,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) memset(nskb->cb, 0, sizeof(nskb->cb)); - ieee80211_tx_skb(rx->sdata, nskb); + if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb); + + info->flags = IEEE80211_TX_CTL_TX_OFFCHAN | + IEEE80211_TX_INTFL_OFFCHAN_TX_OK | + IEEE80211_TX_CTL_NO_CCK_RATE; + if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) + info->hw_queue = + local->hw.offchannel_tx_hw_queue; + } + + __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, + status->band); } dev_kfree_skb(rx->skb); return RX_QUEUED; -- cgit v1.2.3 From 1540c85b176180e5e0b312dd98db7f438baf8a24 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 7 Mar 2013 16:47:23 +0530 Subject: ARC: make allyesconfig build breakages CC drivers/mmc/host/mmc_spi.o drivers/mmc/host/mmc_spi.c:118: error: redefinition of 'struct scratch' make[3]: *** [drivers/mmc/host/mmc_spi.o] Error 1 make[2]: *** [drivers/mmc/host] Error 2 make[1]: *** [drivers/mmc] Error 2 make: *** [drivers] Error 2 CC arch/arc/kernel/kgdb.o In file included from include/linux/kgdb.h:20, from arch/arc/kernel/kgdb.c:11: /home/vineetg/arc/k.org/arc-port/arch/arc/include/asm/kgdb.h:34: warning: 'struct pt_regs' declared inside parameter list /home/vineetg/arc/k.org/arc-port/arch/arc/include/asm/kgdb.h:34: warning: its scope is only this definition or declaration, which is probably not what you want arch/arc/kernel/kgdb.c:172: error: conflicting types for 'kgdb_trap' CC arch/arc/kernel/kgdb.o arch/arc/kernel/kgdb.c: In function 'pt_regs_to_gdb_regs': arch/arc/kernel/kgdb.c:62: error: dereferencing pointer to incomplete type Signed-off-by: Vineet Gupta --- arch/arc/include/asm/kgdb.h | 6 ++---- arch/arc/include/uapi/asm/ptrace.h | 4 ++-- arch/arc/kernel/kgdb.c | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h index f3c4934f0ca9..4930957ca3d3 100644 --- a/arch/arc/include/asm/kgdb.h +++ b/arch/arc/include/asm/kgdb.h @@ -13,7 +13,7 @@ #ifdef CONFIG_KGDB -#include +#include /* to ensure compatibility with Linux 2.6.35, we don't implement the get/set * register API yet */ @@ -53,9 +53,7 @@ enum arc700_linux_regnums { }; #else -static inline void kgdb_trap(struct pt_regs *regs, int param) -{ -} +#define kgdb_trap(regs, param) #endif #endif /* __ARC_KGDB_H__ */ diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 6afa4f702075..30333cec0fef 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -28,14 +28,14 @@ */ struct user_regs_struct { - struct scratch { + struct { long pad; long bta, lp_start, lp_end, lp_count; long status32, ret, blink, fp, gp; long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; long sp; } scratch; - struct callee { + struct { long pad; long r25, r24, r23, r22, r21, r20; long r19, r18, r17, r16, r15, r14, r13; diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c index 2888ba5be47e..52bdc83c1495 100644 --- a/arch/arc/kernel/kgdb.c +++ b/arch/arc/kernel/kgdb.c @@ -9,6 +9,7 @@ */ #include +#include #include #include -- cgit v1.2.3 From 8ff14bbc6a2083e83c6d387d025fb67ba639807c Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 6 Mar 2013 14:33:27 +0530 Subject: ARC: ABIv3: Print the correct ABI ver Signed-off-by: Vineet Gupta --- arch/arc/kernel/setup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index dc0f968dae0a..2d95ac07df7b 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -232,10 +232,8 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len) n += scnprintf(buf + n, len - n, "\n"); -#ifdef _ASM_GENERIC_UNISTD_H n += scnprintf(buf + n, len - n, - "OS ABI [v2]\t: asm-generic/{unistd,stat,fcntl}\n"); -#endif + "OS ABI [v3]\t: no-legacy-syscalls\n"); return buf; } -- cgit v1.2.3 From 180d406e4948faee6e63781f3e062f40ec7c6fc3 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 4 Mar 2013 16:01:35 +0530 Subject: ARC: ABIv3: fork/vfork wrappers not needed in "no-legacy-syscall" ABI When switching to clone() only ABI - I missed out pruning the low level asm syscall wrappers Signed-off-by: Vineet Gupta --- arch/arc/include/asm/syscalls.h | 2 -- arch/arc/kernel/entry.S | 25 ------------------------- arch/arc/kernel/sys.c | 2 -- 3 files changed, 29 deletions(-) diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h index e53a5340ba4f..dd785befe7fd 100644 --- a/arch/arc/include/asm/syscalls.h +++ b/arch/arc/include/asm/syscalls.h @@ -16,8 +16,6 @@ #include int sys_clone_wrapper(int, int, int, int, int); -int sys_fork_wrapper(void); -int sys_vfork_wrapper(void); int sys_cacheflush(uint32_t, uint32_t uint32_t); int sys_arc_settls(void *); int sys_arc_gettls(void); diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index ef6800ba2f03..b9d875a441cc 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -792,31 +792,6 @@ ARC_EXIT ret_from_fork ;################### Special Sys Call Wrappers ########################## -; TBD: call do_fork directly from here -ARC_ENTRY sys_fork_wrapper - SAVE_CALLEE_SAVED_USER - bl @sys_fork - DISCARD_CALLEE_SAVED_USER - - GET_CURR_THR_INFO_FLAGS r10 - btst r10, TIF_SYSCALL_TRACE - bnz tracesys_exit - - b ret_from_system_call -ARC_EXIT sys_fork_wrapper - -ARC_ENTRY sys_vfork_wrapper - SAVE_CALLEE_SAVED_USER - bl @sys_vfork - DISCARD_CALLEE_SAVED_USER - - GET_CURR_THR_INFO_FLAGS r10 - btst r10, TIF_SYSCALL_TRACE - bnz tracesys_exit - - b ret_from_system_call -ARC_EXIT sys_vfork_wrapper - ARC_ENTRY sys_clone_wrapper SAVE_CALLEE_SAVED_USER bl @sys_clone diff --git a/arch/arc/kernel/sys.c b/arch/arc/kernel/sys.c index f6bdd07583f3..9d6c1ca26af6 100644 --- a/arch/arc/kernel/sys.c +++ b/arch/arc/kernel/sys.c @@ -6,8 +6,6 @@ #include #define sys_clone sys_clone_wrapper -#define sys_fork sys_fork_wrapper -#define sys_vfork sys_vfork_wrapper #undef __SYSCALL #define __SYSCALL(nr, call) [nr] = (call), -- cgit v1.2.3 From 63981a4096081f3a35351f56fa89e91f493c02c7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 22 Jan 2013 10:58:21 +0100 Subject: MIPS: compat: Return same error ENOSYS as native for invalid operation. The pains for multiplexed syscalls. Noticed by Al Viro . Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 8eeee1c860c0..db9655f08892 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -171,7 +171,7 @@ SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third, err = compat_sys_shmctl(first, second, compat_ptr(ptr)); break; default: - err = -EINVAL; + err = -ENOSYS; break; } -- cgit v1.2.3 From 0e367ae46503cfe7791460c8ba8434a5d60b2bd5 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 7 Mar 2013 17:32:01 +0000 Subject: xen/blkback: correctly respond to unknown, non-native requests If the frontend is using a non-native protocol (e.g., a 64-bit frontend with a 32-bit backend) and it sent an unrecognized request, the request was not translated and the response would have the incorrect ID. This may cause the frontend driver to behave incorrectly or crash. Since the ID field in the request is always in the same place, regardless of the request type we can get the correct ID and make a valid response (which will report BLKIF_RSP_EOPNOTSUPP). This bug affected 64-bit SLES 11 guests when using a 32-bit backend. This guest does a BLKIF_OP_RESERVED_1 (BLKIF_OP_PACKET in the SLES source) and would crash in blkif_int() as the ID in the response would be invalid. Signed-off-by: David Vrabel Cc: stable@vger.kernel.org Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 31 +++++++++++++++++++++++++++---- drivers/block/xen-blkback/common.h | 25 +++++++++++++++++++++++++ include/xen/interface/io/blkif.h | 10 ++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 6d1cc3df2ac6..1a0faf6370ca 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -679,6 +679,16 @@ static int dispatch_discard_io(struct xen_blkif *blkif, return err; } +static int dispatch_other_io(struct xen_blkif *blkif, + struct blkif_request *req, + struct pending_req *pending_req) +{ + free_req(pending_req); + make_response(blkif, req->u.other.id, req->operation, + BLKIF_RSP_EOPNOTSUPP); + return -EIO; +} + static void xen_blk_drain_io(struct xen_blkif *blkif) { atomic_set(&blkif->drain, 1); @@ -800,17 +810,30 @@ __do_block_io_op(struct xen_blkif *blkif) /* Apply all sanity checks to /private copy/ of request. */ barrier(); - if (unlikely(req.operation == BLKIF_OP_DISCARD)) { + + switch (req.operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + if (dispatch_rw_block_io(blkif, &req, pending_req)) + goto done; + break; + case BLKIF_OP_DISCARD: free_req(pending_req); if (dispatch_discard_io(blkif, &req)) - break; - } else if (dispatch_rw_block_io(blkif, &req, pending_req)) + goto done; + break; + default: + if (dispatch_other_io(blkif, &req, pending_req)) + goto done; break; + } /* Yield point for this unbounded loop. */ cond_resched(); } - +done: return more_to_do; } diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 6072390c7f57..195278ae993d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -77,11 +77,18 @@ struct blkif_x86_32_request_discard { uint64_t nr_sectors; } __attribute__((__packed__)); +struct blkif_x86_32_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_x86_32_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_x86_32_request_rw rw; struct blkif_x86_32_request_discard discard; + struct blkif_x86_32_request_other other; } u; } __attribute__((__packed__)); @@ -113,11 +120,19 @@ struct blkif_x86_64_request_discard { uint64_t nr_sectors; } __attribute__((__packed__)); +struct blkif_x86_64_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; + uint32_t _pad3; /* offsetof(blkif_..,u.discard.id)==8 */ + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_x86_64_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_x86_64_request_rw rw; struct blkif_x86_64_request_discard discard; + struct blkif_x86_64_request_other other; } u; } __attribute__((__packed__)); @@ -278,6 +293,11 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; break; } } @@ -309,6 +329,11 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; break; } } diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h index 01c3d62436ef..ffd4652de91c 100644 --- a/include/xen/interface/io/blkif.h +++ b/include/xen/interface/io/blkif.h @@ -138,11 +138,21 @@ struct blkif_request_discard { uint8_t _pad3; } __attribute__((__packed__)); +struct blkif_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; /* only for read/write requests */ +#ifdef CONFIG_X86_64 + uint32_t _pad3; /* offsetof(blkif_req..,u.other.id)==8*/ +#endif + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_request_rw rw; struct blkif_request_discard discard; + struct blkif_request_other other; } u; } __attribute__((__packed__)); -- cgit v1.2.3 From 986cacbd26abe5d498be922cd6632f1ec376c271 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Mon, 11 Mar 2013 16:15:50 +0000 Subject: xen/blkback: Change statistics counter types to unsigned These values shouldn't be negative, but after an overflow their value can turn into negative, if they are signed. xentop can show bogus values in this case. Signed-off-by: Zoltan Kiss Reported-by: Ichiro Ogino Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 4 ++-- drivers/block/xen-blkback/common.h | 14 +++++++------- drivers/block/xen-blkback/xenbus.c | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 1a0faf6370ca..eaccc222a1dc 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -381,8 +381,8 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id) static void print_stats(struct xen_blkif *blkif) { - pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d" - " | ds %4d\n", + pr_info("xen-blkback (%s): oo %3llu | rd %4llu | wr %4llu | f %4llu" + " | ds %4llu\n", current->comm, blkif->st_oo_req, blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req, blkif->st_ds_req); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 195278ae993d..da78346487ae 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -223,13 +223,13 @@ struct xen_blkif { /* statistics */ unsigned long st_print; - int st_rd_req; - int st_wr_req; - int st_oo_req; - int st_f_req; - int st_ds_req; - int st_rd_sect; - int st_wr_sect; + unsigned long long st_rd_req; + unsigned long long st_wr_req; + unsigned long long st_oo_req; + unsigned long long st_f_req; + unsigned long long st_ds_req; + unsigned long long st_rd_sect; + unsigned long long st_wr_sect; wait_queue_head_t waiting_to_free; }; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 5e237f630c47..8bfd1bcf95ec 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -230,13 +230,13 @@ int __init xen_blkif_interface_init(void) } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) -VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req); -VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req); -VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req); -VBD_SHOW(f_req, "%d\n", be->blkif->st_f_req); -VBD_SHOW(ds_req, "%d\n", be->blkif->st_ds_req); -VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect); -VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect); +VBD_SHOW(oo_req, "%llu\n", be->blkif->st_oo_req); +VBD_SHOW(rd_req, "%llu\n", be->blkif->st_rd_req); +VBD_SHOW(wr_req, "%llu\n", be->blkif->st_wr_req); +VBD_SHOW(f_req, "%llu\n", be->blkif->st_f_req); +VBD_SHOW(ds_req, "%llu\n", be->blkif->st_ds_req); +VBD_SHOW(rd_sect, "%llu\n", be->blkif->st_rd_sect); +VBD_SHOW(wr_sect, "%llu\n", be->blkif->st_wr_sect); static struct attribute *xen_vbdstat_attrs[] = { &dev_attr_oo_req.attr, -- cgit v1.2.3 From f37912039eb04979f269de0a7dc1a601702df51a Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Mon, 25 Feb 2013 12:27:46 -0600 Subject: block: IBM RamSan 70/80 trivial changes. This patch includes trivial changes that were recommended by different members of the Linux Community. Changes include: o Removing the redundant wmb(). o Formatting o Various other little things. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/config.c | 6 ++---- drivers/block/rsxx/core.c | 4 ++-- drivers/block/rsxx/cregs.c | 13 +++---------- drivers/block/rsxx/dma.c | 12 ------------ drivers/block/rsxx/rsxx.h | 6 ++++-- 5 files changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/block/rsxx/config.c b/drivers/block/rsxx/config.c index a295e7e9ee41..0d8cb18284eb 100644 --- a/drivers/block/rsxx/config.c +++ b/drivers/block/rsxx/config.c @@ -29,10 +29,8 @@ #include "rsxx_priv.h" #include "rsxx_cfg.h" -static void initialize_config(void *config) +static void initialize_config(struct rsxx_card_cfg *cfg) { - struct rsxx_card_cfg *cfg = config; - cfg->hdr.version = RSXX_CFG_VERSION; cfg->data.block_size = RSXX_HW_BLK_SIZE; @@ -181,7 +179,7 @@ int rsxx_load_config(struct rsxx_cardinfo *card) } else { dev_info(CARD_TO_DEV(card), "Initializing card configuration.\n"); - initialize_config(card); + initialize_config(&card->config); st = rsxx_save_config(card); if (st) return st; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index e5162487686a..edbae10e7f6f 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -161,9 +161,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata) } /*----------------- Card Event Handler -------------------*/ -static char *rsxx_card_state_to_str(unsigned int state) +static const char * const rsxx_card_state_to_str(unsigned int state) { - static char *state_strings[] = { + static const char * const state_strings[] = { "Unknown", "Shutdown", "Starting", "Formatting", "Uninitialized", "Good", "Shutting Down", "Fault", "Read Only Fault", "dStroying" diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index 80bbe639fccd..224156435261 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -126,13 +126,6 @@ static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) cmd->buf, cmd->stream); } - /* - * Data copy must complete before initiating the command. This is - * needed for weakly ordered processors (i.e. PowerPC), so that all - * neccessary registers are written before we kick the hardware. - */ - wmb(); - /* Setting the valid bit will kick off the command. */ iowrite32(cmd->op, card->regmap + CREG_CMD); } @@ -399,12 +392,12 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card, return st; /* - * This timeout is neccessary for unresponsive hardware. The additional + * This timeout is necessary for unresponsive hardware. The additional * 20 seconds to used to guarantee that each cregs requests has time to * complete. */ - timeout = msecs_to_jiffies((CREG_TIMEOUT_MSEC * - card->creg_ctrl.q_depth) + 20000); + timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC * + card->creg_ctrl.q_depth + 20000); /* * The creg interface is guaranteed to complete. It has a timeout diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 63176e67662f..7c3a57bed2cd 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -432,16 +432,6 @@ static void rsxx_issue_dmas(struct work_struct *work) /* Let HW know we've queued commands. */ if (cmds_pending) { - /* - * We must guarantee that the CPU writes to 'ctrl->cmd.buf' - * (which is in PCI-consistent system-memory) from the loop - * above make it into the coherency domain before the - * following PIO "trigger" updating the cmd.idx. A WMB is - * sufficient. We need not explicitly CPU cache-flush since - * the memory is a PCI-consistent (ie; coherent) mapping. - */ - wmb(); - atomic_add(cmds_pending, &ctrl->stats.hw_q_depth); mod_timer(&ctrl->activity_timer, jiffies + DMA_ACTIVITY_TIMEOUT); @@ -798,8 +788,6 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev, iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX); iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); - wmb(); - return 0; } diff --git a/drivers/block/rsxx/rsxx.h b/drivers/block/rsxx/rsxx.h index 2e50b65902b7..24ba3642bd89 100644 --- a/drivers/block/rsxx/rsxx.h +++ b/drivers/block/rsxx/rsxx.h @@ -27,15 +27,17 @@ /*----------------- IOCTL Definitions -------------------*/ +#define RSXX_MAX_DATA 8 + struct rsxx_reg_access { __u32 addr; __u32 cnt; __u32 stat; __u32 stream; - __u32 data[8]; + __u32 data[RSXX_MAX_DATA]; }; -#define RSXX_MAX_REG_CNT (8 * (sizeof(__u32))) +#define RSXX_MAX_REG_CNT (RSXX_MAX_DATA * (sizeof(__u32))) #define RSXX_IOC_MAGIC 'r' -- cgit v1.2.3 From 03ac03a8971bd7e9f8c8b20a309b61beaf154d60 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Mon, 25 Feb 2013 12:31:31 -0600 Subject: block: IBM RamSan 70/80 fixes inconsistent locking. This patch includes changes to the cregs locking scheme. Before, inconsistant locking would occur because of misuse of spin_lock, spin_lock_bh, and counter parts. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/cregs.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index 224156435261..0539a25877eb 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -99,22 +99,6 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card, } } -static struct creg_cmd *pop_active_cmd(struct rsxx_cardinfo *card) -{ - struct creg_cmd *cmd; - - /* - * Spin lock is needed because this can be called in atomic/interrupt - * context. - */ - spin_lock_bh(&card->creg_ctrl.lock); - cmd = card->creg_ctrl.active_cmd; - card->creg_ctrl.active_cmd = NULL; - spin_unlock_bh(&card->creg_ctrl.lock); - - return cmd; -} - static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) { iowrite32(cmd->addr, card->regmap + CREG_ADD); @@ -189,11 +173,11 @@ static int creg_queue_cmd(struct rsxx_cardinfo *card, cmd->cb_private = cb_private; cmd->status = 0; - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_add_tail(&cmd->list, &card->creg_ctrl.queue); card->creg_ctrl.q_depth++; creg_kick_queue(card); - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); return 0; } @@ -203,7 +187,11 @@ static void creg_cmd_timed_out(unsigned long data) struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data; struct creg_cmd *cmd; - cmd = pop_active_cmd(card); + spin_lock(&card->creg_ctrl.lock); + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + spin_unlock(&card->creg_ctrl.lock); + if (cmd == NULL) { card->creg_ctrl.creg_stats.creg_timeout++; dev_warn(CARD_TO_DEV(card), @@ -240,7 +228,11 @@ static void creg_cmd_done(struct work_struct *work) if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0) card->creg_ctrl.creg_stats.failed_cancel_timer++; - cmd = pop_active_cmd(card); + spin_lock_bh(&card->creg_ctrl.lock); + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + spin_unlock_bh(&card->creg_ctrl.lock); + if (cmd == NULL) { dev_err(CARD_TO_DEV(card), "Spurious creg interrupt!\n"); @@ -289,10 +281,10 @@ creg_done: kmem_cache_free(creg_cmd_pool, cmd); - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); } static void creg_reset(struct rsxx_cardinfo *card) @@ -317,7 +309,7 @@ static void creg_reset(struct rsxx_cardinfo *card) "Resetting creg interface for recovery\n"); /* Cancel outstanding commands */ - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); card->creg_ctrl.q_depth--; @@ -338,7 +330,7 @@ static void creg_reset(struct rsxx_cardinfo *card) card->creg_ctrl.active = 0; } - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); card->creg_ctrl.reset = 0; spin_lock_irqsave(&card->irq_lock, flags); @@ -705,7 +697,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) int cnt = 0; /* Cancel outstanding commands */ - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); if (cmd->cb) @@ -730,7 +722,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) "Canceled active creg command\n"); kmem_cache_free(creg_cmd_pool, cmd); } - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); cancel_work_sync(&card->creg_ctrl.done_work); } -- cgit v1.2.3 From 9bb3c4469e317919b0fde8c0e0a3ebe7bd2cf167 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Wed, 27 Feb 2013 09:24:59 -0600 Subject: block: IBM RamSan 70/80 branding changes. This patch includes changing the hardware branding name from IBM RamSan to IBM FlashSystem. v2 Changes include: o Removing the unnecessary IBM Vendor ID #define v1 Changes include: o Changed all references of RamSan to FlashSystem. o Changed the vendor/device IDs for the product. o Changed driver version number. o Updated the MAINTAINERS file. o Various other little things. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- MAINTAINERS | 12 ++++++------ drivers/block/Kconfig | 4 ++-- drivers/block/rsxx/Makefile | 2 +- drivers/block/rsxx/config.c | 2 +- drivers/block/rsxx/core.c | 10 ++++------ drivers/block/rsxx/dma.c | 2 +- drivers/block/rsxx/rsxx_cfg.h | 2 +- drivers/block/rsxx/rsxx_priv.h | 9 +++------ 8 files changed, 19 insertions(+), 24 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 95616582c728..a00f0eaf0eda 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3242,6 +3242,12 @@ F: Documentation/firmware_class/ F: drivers/base/firmware*.c F: include/linux/firmware.h +FLASHSYSTEM DRIVER (IBM FlashSystem 70/80 PCI SSD Flash Card) +M: Joshua Morris +M: Philip Kelleher +S: Maintained +F: drivers/block/rsxx/ + FLOPPY DRIVER M: Jiri Kosina T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git @@ -6516,12 +6522,6 @@ S: Maintained F: Documentation/blockdev/ramdisk.txt F: drivers/block/brd.c -RAMSAM DRIVER (IBM RamSan 70/80 PCI SSD Flash Card) -M: Joshua Morris -M: Philip Kelleher -S: Maintained -F: drivers/block/rsxx/ - RANDOM NUMBER DRIVER M: Theodore Ts'o" S: Maintained diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5dc0daed8fac..b81ddfea1da0 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -532,11 +532,11 @@ config BLK_DEV_RBD If unsure, say N. config BLK_DEV_RSXX - tristate "RamSam PCIe Flash SSD Device Driver" + tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver" depends on PCI help Device driver for IBM's high speed PCIe SSD - storage devices: RamSan-70 and RamSan-80. + storage devices: FlashSystem-70 and FlashSystem-80. To compile this driver as a module, choose M here: the module will be called rsxx. diff --git a/drivers/block/rsxx/Makefile b/drivers/block/rsxx/Makefile index f35cd0b71f7b..b1c53c0aa450 100644 --- a/drivers/block/rsxx/Makefile +++ b/drivers/block/rsxx/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_BLK_DEV_RSXX) += rsxx.o -rsxx-y := config.o core.o cregs.o dev.o dma.o +rsxx-objs := config.o core.o cregs.o dev.o dma.o diff --git a/drivers/block/rsxx/config.c b/drivers/block/rsxx/config.c index 0d8cb18284eb..10cd530d3e10 100644 --- a/drivers/block/rsxx/config.c +++ b/drivers/block/rsxx/config.c @@ -35,7 +35,7 @@ static void initialize_config(struct rsxx_card_cfg *cfg) cfg->data.block_size = RSXX_HW_BLK_SIZE; cfg->data.stripe_size = RSXX_HW_BLK_SIZE; - cfg->data.vendor_id = RSXX_VENDOR_ID_TMS_IBM; + cfg->data.vendor_id = RSXX_VENDOR_ID_IBM; cfg->data.cache_order = (-1); cfg->data.intr_coal.mode = RSXX_INTR_COAL_DISABLED; cfg->data.intr_coal.count = 0; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index edbae10e7f6f..b82ee7baf0e8 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -39,8 +39,8 @@ #define NO_LEGACY 0 -MODULE_DESCRIPTION("IBM RamSan PCIe Flash SSD Device Driver"); -MODULE_AUTHOR("IBM "); +MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver"); +MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); @@ -593,10 +593,8 @@ static void rsxx_pci_shutdown(struct pci_dev *dev) } static DEFINE_PCI_DEVICE_TABLE(rsxx_pci_ids) = { - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70D_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS80_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS81_FLASH)}, + {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS70_FLASH)}, + {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS80_FLASH)}, {0,}, }; diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 7c3a57bed2cd..efd75b55a670 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -28,7 +28,7 @@ struct rsxx_dma { struct list_head list; u8 cmd; - unsigned int laddr; /* Logical address on the ramsan */ + unsigned int laddr; /* Logical address */ struct { u32 off; u32 cnt; diff --git a/drivers/block/rsxx/rsxx_cfg.h b/drivers/block/rsxx/rsxx_cfg.h index c025fe5fdb70..f384c943846d 100644 --- a/drivers/block/rsxx/rsxx_cfg.h +++ b/drivers/block/rsxx/rsxx_cfg.h @@ -58,7 +58,7 @@ struct rsxx_card_cfg { }; /* Vendor ID Values */ -#define RSXX_VENDOR_ID_TMS_IBM 0 +#define RSXX_VENDOR_ID_IBM 0 #define RSXX_VENDOR_ID_DSI 1 #define RSXX_VENDOR_COUNT 2 diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index a1ac907d8f4c..f5a95f75bd57 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -45,16 +45,13 @@ struct proc_cmd; -#define PCI_VENDOR_ID_TMS_IBM 0x15B6 -#define PCI_DEVICE_ID_RS70_FLASH 0x0019 -#define PCI_DEVICE_ID_RS70D_FLASH 0x001A -#define PCI_DEVICE_ID_RS80_FLASH 0x001C -#define PCI_DEVICE_ID_RS81_FLASH 0x001E +#define PCI_DEVICE_ID_FS70_FLASH 0x04A9 +#define PCI_DEVICE_ID_FS80_FLASH 0x04AA #define RS70_PCI_REV_SUPPORTED 4 #define DRIVER_NAME "rsxx" -#define DRIVER_VERSION "3.7" +#define DRIVER_VERSION "4.0" /* Block size is 4096 */ #define RSXX_HW_BLK_SHIFT 12 -- cgit v1.2.3 From 1ebfd109822ea35b71aee4efe9ddc2e1b9ac0ed7 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Mon, 25 Feb 2013 13:09:40 -0600 Subject: block: IBM RamSan 70/80 error message bug fix. This patch includes a simple change to the rsxx_pci_remove function that caused error messages because traffic was halted too early. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index b82ee7baf0e8..cbbdff113f46 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -538,9 +538,6 @@ static void rsxx_pci_remove(struct pci_dev *dev) rsxx_disable_ier_and_isr(card, CR_INTR_EVENT); spin_unlock_irqrestore(&card->irq_lock, flags); - /* Prevent work_structs from re-queuing themselves. */ - card->halt = 1; - cancel_work_sync(&card->event_work); rsxx_destroy_dev(card); @@ -549,6 +546,10 @@ static void rsxx_pci_remove(struct pci_dev *dev) spin_lock_irqsave(&card->irq_lock, flags); rsxx_disable_ier_and_isr(card, CR_INTR_ALL); spin_unlock_irqrestore(&card->irq_lock, flags); + + /* Prevent work_structs from re-queuing themselves. */ + card->halt = 1; + free_irq(dev->irq, card); if (!force_legacy) -- cgit v1.2.3 From e744109fce4b9581acdc23287667e240bcd239b7 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Mar 2013 11:39:35 +0000 Subject: MIPS: Use CONFIG_CPU_MIPSR2 in csum_partial.S The csum_partial implementation contain optimalizations for the MIPS R2 instruction set. This optimization is never enabled however because the if directive uses the CPU_MIPSR2 constant which is not defined anywhere. Use the CONFIG_CPU_MIPSR2 constant instead. Signed-off-by: Gabor Juhos Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/4971/ Signed-off-by: Ralf Baechle --- arch/mips/lib/csum_partial.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S index 507147aebd41..a6adffbb4e5f 100644 --- a/arch/mips/lib/csum_partial.S +++ b/arch/mips/lib/csum_partial.S @@ -270,7 +270,7 @@ LEAF(csum_partial) #endif /* odd buffer alignment? */ -#ifdef CPU_MIPSR2 +#ifdef CONFIG_CPU_MIPSR2 wsbh v1, sum movn sum, v1, t7 #else @@ -670,7 +670,7 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc) addu sum, v1 #endif -#ifdef CPU_MIPSR2 +#ifdef CONFIG_CPU_MIPSR2 wsbh v1, sum movn sum, v1, odd #else -- cgit v1.2.3 From 0c81157b46c533139d6be721d41617020c59a2c3 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 26 Feb 2013 14:35:23 -0800 Subject: MIPS: Fix logic errors in bitops.c commit 92d11594f6 (MIPS: Remove irqflags.h dependency from bitops.h) factored some of the bitops code out into a separate file (arch/mips/lib/bitops.c). Unfortunately the logic converting a bit mask into a boolean result was lost in some of the functions. We had: int res; unsigned long shifted_result_bit; . . . res = shifted_result_bit; return res; Which truncates off the high 32 bits (thus yielding an incorrect value) on 64-bit systems. The manifestation of this is that a non-SMP 64-bit kernel will not boot as the bitmap operations in bootmem.c are all screwed up. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: Jim Quinlan Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/4965/ Signed-off-by: Ralf Baechle --- arch/mips/lib/bitops.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/mips/lib/bitops.c b/arch/mips/lib/bitops.c index 81f1dcfdcab8..a64daee740ee 100644 --- a/arch/mips/lib/bitops.c +++ b/arch/mips/lib/bitops.c @@ -90,12 +90,12 @@ int __mips_test_and_set_bit(unsigned long nr, unsigned bit = nr & SZLONG_MASK; unsigned long mask; unsigned long flags; - unsigned long res; + int res; a += nr >> SZLONG_LOG; mask = 1UL << bit; raw_local_irq_save(flags); - res = (mask & *a); + res = (mask & *a) != 0; *a |= mask; raw_local_irq_restore(flags); return res; @@ -116,12 +116,12 @@ int __mips_test_and_set_bit_lock(unsigned long nr, unsigned bit = nr & SZLONG_MASK; unsigned long mask; unsigned long flags; - unsigned long res; + int res; a += nr >> SZLONG_LOG; mask = 1UL << bit; raw_local_irq_save(flags); - res = (mask & *a); + res = (mask & *a) != 0; *a |= mask; raw_local_irq_restore(flags); return res; @@ -141,12 +141,12 @@ int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr) unsigned bit = nr & SZLONG_MASK; unsigned long mask; unsigned long flags; - unsigned long res; + int res; a += nr >> SZLONG_LOG; mask = 1UL << bit; raw_local_irq_save(flags); - res = (mask & *a); + res = (mask & *a) != 0; *a &= ~mask; raw_local_irq_restore(flags); return res; @@ -166,12 +166,12 @@ int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr) unsigned bit = nr & SZLONG_MASK; unsigned long mask; unsigned long flags; - unsigned long res; + int res; a += nr >> SZLONG_LOG; mask = 1UL << bit; raw_local_irq_save(flags); - res = (mask & *a); + res = (mask & *a) != 0; *a ^= mask; raw_local_irq_restore(flags); return res; -- cgit v1.2.3 From 9f91e5064c6c24d6ccd760a6b6120de4560d9829 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 21 Feb 2013 15:38:19 +0900 Subject: MIPS: VR4133: Fix probe for LL/SC. Signed-off-by: Yoichi Yuasa Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/4963/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 6bfccc227a95..d069a19112e8 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -580,6 +580,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->tlbsize = 48; break; case PRID_IMP_VR41XX: + set_isa(c, MIPS_CPU_ISA_III); + c->options = R4K_OPTS; + c->tlbsize = 32; switch (c->processor_id & 0xf0) { case PRID_REV_VR4111: c->cputype = CPU_VR4111; @@ -604,6 +607,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "NEC VR4131"; } else { c->cputype = CPU_VR4133; + c->options |= MIPS_CPU_LLSC; __cpu_name[cpu] = "NEC VR4133"; } break; @@ -613,9 +617,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "NEC Vr41xx"; break; } - set_isa(c, MIPS_CPU_ISA_III); - c->options = R4K_OPTS; - c->tlbsize = 32; break; case PRID_IMP_R4300: c->cputype = CPU_R4300; -- cgit v1.2.3 From 383c97b4587665d47d08dff37ec85b44be760505 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 4 Mar 2013 04:17:21 +0000 Subject: MIPS: Add dependencies for HAVE_ARCH_TRANSPARENT_HUGEPAGE The MIPS implementation of transparent huge-pages (THP) is 64-bit only, and of course also requires that the CPU supports huge-pages. Currently it's entirely possible to enable THP in other configurations, which then fail to build due to pfn_pmd() not being defined. Signed-off-by: Ben Hutchings Cc: linux-mips@linux-mips.org Acked-by: David Daney Patchwork: https://patchwork.linux-mips.org/patch/4972/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ae9c716c46bb..e8e10b794b87 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -18,7 +18,7 @@ config MIPS select HAVE_KRETPROBES select HAVE_DEBUG_KMEMLEAK select ARCH_BINFMT_ELF_RANDOMIZE_PIE - select HAVE_ARCH_TRANSPARENT_HUGEPAGE + select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT select RTC_LIB if !MACH_LOONGSON select GENERIC_ATOMIC64 if !64BIT select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE -- cgit v1.2.3 From 631b0af98c1efb160f02154743ae9f13fe03e347 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 5 Mar 2013 13:20:20 +0100 Subject: MIPS: Get rid of CONFIG_CPU_HAS_LLSC again Commit f7ade3c168e4f437c11f57be012992bbb0e3075c ("MIPS: Get rid of CONFIG_CPU_HAS_LLSC") did what it promised to do. But since then that macro and its Kconfig symbol popped up again. Get rid of those again. Signed-off-by: Paul Bolle Cc: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/4978/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 - arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e8e10b794b87..1a166d98773e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1493,7 +1493,6 @@ config CPU_XLP select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM - select CPU_HAS_LLSC select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC select CPU_HAS_PREFETCH diff --git a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h index d9c828419037..b40f37fb3dee 100644 --- a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h @@ -28,11 +28,7 @@ /* #define cpu_has_prefetch ? */ #define cpu_has_mcheck 1 /* #define cpu_has_ejtag ? */ -#ifdef CONFIG_CPU_HAS_LLSC -#define cpu_has_llsc 1 -#else #define cpu_has_llsc 0 -#endif /* #define cpu_has_vtag_icache ? */ /* #define cpu_has_dc_aliases ? */ /* #define cpu_has_ic_fills_f_dc ? */ -- cgit v1.2.3 From f4cdb6a00c148e7724ada0998643b293a52b5f62 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Mar 2013 16:06:07 +0100 Subject: MIPS: SEAD3: Enable LL/SC. All synthesizable CPU cores that could be loaded into a SEAD3's FPGA are MIPS32 or MIPS64 CPUs that have ll/sc. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h index b40f37fb3dee..193c0912d38e 100644 --- a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h @@ -28,7 +28,7 @@ /* #define cpu_has_prefetch ? */ #define cpu_has_mcheck 1 /* #define cpu_has_ejtag ? */ -#define cpu_has_llsc 0 +#define cpu_has_llsc 1 /* #define cpu_has_vtag_icache ? */ /* #define cpu_has_dc_aliases ? */ /* #define cpu_has_ic_fills_f_dc ? */ -- cgit v1.2.3 From c300d6de53ae029576b2805f08d8596d2e511b08 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Mar 2013 21:36:24 +0800 Subject: ASoC: tas5086: use module_i2c_driver to simplify the code Use the module_i2c_driver() macro to make the code smaller and a bit simpler. Signed-off-by: Wei Yongjun Acked-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tas5086.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 008bea4d6208..40cee844f0cf 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -584,17 +584,7 @@ static struct i2c_driver tas5086_i2c_driver = { .remove = tas5086_i2c_remove, }; -static int __init tas5086_modinit(void) -{ - return i2c_add_driver(&tas5086_i2c_driver); -} -module_init(tas5086_modinit); - -static void __exit tas5086_modexit(void) -{ - i2c_del_driver(&tas5086_i2c_driver); -} -module_exit(tas5086_modexit); +module_i2c_driver(tas5086_i2c_driver); MODULE_AUTHOR("Daniel Mack "); MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver"); -- cgit v1.2.3 From c6432ea9cc043994d5b7dcb3ad86a087777cb40c Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Mon, 11 Mar 2013 17:27:02 +0000 Subject: regmap: Initialize `map->debugfs' before regcache In the rbtree code we are exposing statistics relating to the number of nodes/registers of the rbtree cache for each of the devices. Ensure that `map->debugfs' has been initialized before we attempt to initialize the debugfs entry for the rbtree cache. Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/base/regmap/regmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 3d2367501fd0..50ef277ea4b6 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -710,12 +710,12 @@ skip_format_initialization: } } + regmap_debugfs_init(map, config->name); + ret = regcache_init(map, config); if (ret != 0) goto err_range; - regmap_debugfs_init(map, config->name); - /* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); if (!m) { -- cgit v1.2.3 From e1328a832c7eeeb4dd3c3666605717c555de9e83 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 7 Mar 2013 17:42:33 -0800 Subject: ASoC: core: remove codec from list if registration failed Current snd_soc_register_codec() adds codec to list, and calls snd_soc_register_dais(). But, this listed codec should be removed if dais registration was failed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e02c374d2243..0ce075c47b25 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4096,6 +4096,10 @@ int snd_soc_register_codec(struct device *dev, return 0; fail_codec_name: + mutex_lock(&client_mutex); + list_del(&codec->list); + mutex_unlock(&client_mutex); + kfree(codec->name); fail_codec: kfree(codec); -- cgit v1.2.3 From 14a1b8ca172f4cfbc544051a729d85a380447a82 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Mon, 11 Mar 2013 13:18:23 -0600 Subject: ASoC: adau1373: adau1373_hw_params: Silence overflow warning ADAU1373_BCLKDIV_SOURCE is defined as BIT(5) which uses UL constants. On amd64 the result of the ones complement operator is then truncated to unsigned int according to the prototype of snd_soc_update_bits(). I think gcc is correctly warning that the upper 32 bits are lost. sound/soc/codecs/adau1373.c: In function 'adau1373_hw_params': sound/soc/codecs/adau1373.c:940:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] gcc version 4.6.3 Add 2 more BCLKDIV mask macros as explained by Lars: The BCLKDIV has three fields. The bitclock divider (bit 0-1), the samplerate (bit 2-4) and the source select (bit 5). Here we want to update the bitclock divider field and the samplerate field. When I wrote the code I was lazy and used ~ADAU1373_BCLKDIV_SOURCE as the mask, which for this register is functionally equivalent to ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK. Signed-off-by: Tim Gardner Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 068b3ae56a17..1aa10ddf3a61 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -133,6 +133,8 @@ struct adau1373 { #define ADAU1373_DAI_FORMAT_DSP 0x3 #define ADAU1373_BCLKDIV_SOURCE BIT(5) +#define ADAU1373_BCLKDIV_SR_MASK (0x07 << 2) +#define ADAU1373_BCLKDIV_BCLK_MASK 0x03 #define ADAU1373_BCLKDIV_32 0x03 #define ADAU1373_BCLKDIV_64 0x02 #define ADAU1373_BCLKDIV_128 0x01 @@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream, adau1373_dai->enable_src = (div != 0); snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id), - ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64); + ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK, + (div << 2) | ADAU1373_BCLKDIV_64); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: -- cgit v1.2.3 From 1f5353e765fe2a1168477bfe55e4dd7cdd96b477 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Sun, 10 Mar 2013 10:58:21 -0600 Subject: ASoC: wm_hubs: Silence reg_r and reg_l 'may be used uninitialized' warnings Return an error from wm_hubs_read_dc_servo() if hubs->dcs_readback_mode is not correctly initialized. You might as well bail out since nothing is likely to work correctly afterwards. sound/soc/codecs/wm_hubs.c:321:11: warning: 'reg_r' may be used uninitialized in this function [-Wuninitialized] sound/soc/codecs/wm_hubs.c:251:13: note: 'reg_r' was declared here sound/soc/codecs/wm_hubs.c:322:11: warning: 'reg_l' may be used uninitialized in this function [-Wuninitialized] sound/soc/codecs/wm_hubs.c:251:6: note: 'reg_l' was declared here gcc version 4.6.3 Signed-off-by: Tim Gardner Signed-off-by: Mark Brown --- sound/soc/codecs/wm_hubs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 867ae97ddcec..f5d81b948759 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -199,11 +199,12 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg) list_add_tail(&cache->list, &hubs->dcs_cache); } -static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, +static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec, u16 *reg_l, u16 *reg_r) { struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); u16 dcs_reg, reg; + int ret = 0; switch (hubs->dcs_readback_mode) { case 2: @@ -236,8 +237,9 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, break; default: WARN(1, "Unknown DCS readback method\n"); - return; + ret = -1; } + return ret; } /* @@ -286,7 +288,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec) WM8993_DCS_TRIG_STARTUP_1); } - wm_hubs_read_dc_servo(codec, ®_l, ®_r); + if (wm_hubs_read_dc_servo(codec, ®_l, ®_r) < 0) + return; dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); -- cgit v1.2.3 From c1963c37ad4425cbd7a05e386167614efdfdc9ce Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 10 Mar 2013 19:33:02 +0100 Subject: ASoC: imx-ssi: Fix AC97 rates This device supports multiple rates as described in later AC97 standards. This patch allows playback of different sample frequencies without conversion. Signed-off-by: Sascha Hauer Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- sound/soc/fsl/imx-ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 55464a5b0706..7ee0147ec3cd 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -400,7 +400,7 @@ static struct snd_soc_dai_driver imx_ac97_dai = { .stream_name = "AC97 Playback", .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, + .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { -- cgit v1.2.3 From ecf327c7ca5ddcbe611a33c88c19b8be3d0d2322 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 8 Mar 2013 14:19:38 +0100 Subject: ASoC: davinci-mcasp: clean up davinci_hw_common_param() As pointed of by Vaibhav, commit 2952b27e2 ("ASoC: davinci-mcasp: Add support for multichannel playback") duplicated the logic of counting the active serializers. That can be avoided by shifting the code around a bit. Also, drop two unused defines introduced by the same commit. Signed-off-by: Daniel Mack Acked-by: Vaibhav Bedia Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 5cd85a879579..46c9705cec09 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -237,8 +237,6 @@ #define RXSTATE BIT(5) #define SRMOD_MASK 3 #define SRMOD_INACTIVE 0 -#define SRMOD_TX 1 -#define SRMOD_RX 2 /* * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits @@ -686,27 +684,6 @@ static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream, RXDATADMADIS); } - for (i = 0; i < dev->num_serializer; i++) { - if (dev->serial_dir[i] == TX_MODE) - tx_ser++; - if (dev->serial_dir[i] == RX_MODE) - rx_ser++; - } - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - ser = tx_ser; - else - ser = rx_ser; - - if (ser < max_active_serializers) { - dev_warn(dev->dev, "stream has more channels (%d) than are " - "enabled in mcasp (%d)\n", channels, ser * slots); - return -EINVAL; - } - - tx_ser = 0; - rx_ser = 0; - for (i = 0; i < dev->num_serializer; i++) { mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), dev->serial_dir[i]); @@ -726,6 +703,17 @@ static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream, } } + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ser = tx_ser; + else + ser = rx_ser; + + if (ser < max_active_serializers) { + dev_warn(dev->dev, "stream has more channels (%d) than are " + "enabled in mcasp (%d)\n", channels, ser * slots); + return -EINVAL; + } + if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dev->txnumevt * tx_ser > 64) dev->txnumevt = 1; -- cgit v1.2.3 From d558c4733759e077cf449246983a5d1fe97fc434 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 8 Mar 2013 11:51:19 +0530 Subject: spi: slink-tegra20: move runtime pm calls to transfer_one_message The prepare_transfer_hardware() is called in atomic context and calling synchronous runtime pm calls can create scheduling deadlock. Therefore, in place of calling runtime PM calls from prepare/unprepare message transfer, calling this in transfer_one_message(). Signed-off-by: Laxman Dewangan Tested-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index b8698b389ef3..a829563f4713 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -858,21 +858,6 @@ static int tegra_slink_setup(struct spi_device *spi) return 0; } -static int tegra_slink_prepare_transfer(struct spi_master *master) -{ - struct tegra_slink_data *tspi = spi_master_get_devdata(master); - - return pm_runtime_get_sync(tspi->dev); -} - -static int tegra_slink_unprepare_transfer(struct spi_master *master) -{ - struct tegra_slink_data *tspi = spi_master_get_devdata(master); - - pm_runtime_put(tspi->dev); - return 0; -} - static int tegra_slink_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -885,6 +870,12 @@ static int tegra_slink_transfer_one_message(struct spi_master *master, msg->status = 0; msg->actual_length = 0; + ret = pm_runtime_get_sync(tspi->dev); + if (ret < 0) { + dev_err(tspi->dev, "runtime get failed: %d\n", ret); + goto done; + } + single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { INIT_COMPLETION(tspi->xfer_completion); @@ -921,6 +912,8 @@ static int tegra_slink_transfer_one_message(struct spi_master *master, exit: tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); + pm_runtime_put(tspi->dev); +done: msg->status = ret; spi_finalize_current_message(master); return ret; @@ -1148,9 +1141,7 @@ static int tegra_slink_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_slink_setup; - master->prepare_transfer_hardware = tegra_slink_prepare_transfer; master->transfer_one_message = tegra_slink_transfer_one_message; - master->unprepare_transfer_hardware = tegra_slink_unprepare_transfer; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; -- cgit v1.2.3 From 4a25b680b1e84cf97c740c8005e2c6655d6cfa7f Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 12 Mar 2013 00:13:36 +0100 Subject: spi/bcm63xx: Remove unused variable This fixes the following warning: drivers/spi/spi-bcm63xx.c: In function 'bcm63xx_spi_setup': drivers/spi/spi-bcm63xx.c:157:6: warning: unused variable 'ret' Signed-off-by: Kevin Cernekee Acked-by: Florian Fainelli Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 9578af782a77..0415a32cce33 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -152,7 +152,6 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi, static int bcm63xx_spi_setup(struct spi_device *spi) { struct bcm63xx_spi *bs; - int ret; bs = spi_master_get_devdata(spi->master); -- cgit v1.2.3 From b435ff212e91bddc2d12e6638a4d846d5f60daa6 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 12 Mar 2013 00:13:37 +0100 Subject: spi/bcm63xx: don't disable non enabled clocks in probe error path When msg_ctl_width is set to an invalid value we try to disable the clock despite it never being enabled. Fix it by jumping to the correct label. Signed-off-by: Jonas Gorski Acked-by: Florian Fainelli Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 0415a32cce33..d7df435d962e 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -489,7 +489,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) default: dev_err(dev, "unsupported MSG_CTL width: %d\n", bs->msg_ctl_width); - goto out_clk_disable; + goto out_err; } /* Initialize hardware */ -- cgit v1.2.3 From 810d601f07ce2481ff776e049c0733ded2abbcc1 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Feb 2013 10:15:03 +0900 Subject: extcon: max8997: Check the pointer of platform data to protect null pointer error This patch check the pointer of platform data to protect kernel panic when platform data is not used and code clean. Signed-off-by: Chanwoo Choi Signed-off-by: Myungjoo Ham --- drivers/extcon/extcon-max8997.c | 56 +++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index e636d950ad6c..69641bcae325 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev) goto err_irq; } - /* Initialize registers according to platform data */ if (pdata->muic_pdata) { - struct max8997_muic_platform_data *mdata = info->muic_pdata; - - for (i = 0; i < mdata->num_init_data; i++) { - max8997_write_reg(info->muic, mdata->init_data[i].addr, - mdata->init_data[i].data); + struct max8997_muic_platform_data *muic_pdata + = pdata->muic_pdata; + + /* Initialize registers according to platform data */ + for (i = 0; i < muic_pdata->num_init_data; i++) { + max8997_write_reg(info->muic, + muic_pdata->init_data[i].addr, + muic_pdata->init_data[i].data); } - } - /* - * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB - * h/w path of COMP2/COMN1 on CONTROL1 register. - */ - if (pdata->muic_pdata->path_uart) - info->path_uart = pdata->muic_pdata->path_uart; - else - info->path_uart = CONTROL1_SW_UART; + /* + * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB + * h/w path of COMP2/COMN1 on CONTROL1 register. + */ + if (muic_pdata->path_uart) + info->path_uart = muic_pdata->path_uart; + else + info->path_uart = CONTROL1_SW_UART; - if (pdata->muic_pdata->path_usb) - info->path_usb = pdata->muic_pdata->path_usb; - else + if (muic_pdata->path_usb) + info->path_usb = muic_pdata->path_usb; + else + info->path_usb = CONTROL1_SW_USB; + + /* + * Default delay time for detecting cable state + * after certain time. + */ + if (muic_pdata->detcable_delay_ms) + delay_jiffies = + msecs_to_jiffies(muic_pdata->detcable_delay_ms); + else + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } else { + info->path_uart = CONTROL1_SW_UART; info->path_usb = CONTROL1_SW_USB; + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } /* Set initial path for UART */ max8997_muic_set_path(info, info->path_uart, true); @@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev) * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq); - if (pdata->muic_pdata->detcable_delay_ms) - delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms); - else - delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); schedule_delayed_work(&info->wq_detcable, delay_jiffies); return 0; -- cgit v1.2.3 From 190d7cfc8632c10bfbfe756f882b6d9cfddfdf6a Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Feb 2013 10:03:32 +0900 Subject: extcon: max77693: Fix bug of wrong pointer when platform data is not used This patch fix wrong pointer of platform data. If each machine set platform data for h/w path or delay time of workqueue, this driver happen kernel panic related to null pointer. Signed-off-by: Chanwoo Choi Signed-off-by: Myungjoo Ham --- drivers/extcon/extcon-max77693.c | 90 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index b70e3815c459..fea10624f3e5 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1045,7 +1045,6 @@ static int max77693_muic_probe(struct platform_device *pdev) { struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); - struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; struct max77693_muic_info *info; int delay_jiffies; int ret; @@ -1145,44 +1144,63 @@ static int max77693_muic_probe(struct platform_device *pdev) goto err_irq; } - /* Initialize MUIC register by using platform data */ - for (i = 0 ; i < muic_pdata->num_init_data ; i++) { - enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR; - - max77693_write_reg(info->max77693->regmap_muic, - muic_pdata->init_data[i].addr, - muic_pdata->init_data[i].data); - - switch (muic_pdata->init_data[i].addr) { - case MAX77693_MUIC_REG_INTMASK1: - irq_src = MUIC_INT1; - break; - case MAX77693_MUIC_REG_INTMASK2: - irq_src = MUIC_INT2; - break; - case MAX77693_MUIC_REG_INTMASK3: - irq_src = MUIC_INT3; - break; + if (pdata->muic_data) { + struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; + + /* Initialize MUIC register by using platform data */ + for (i = 0 ; i < muic_pdata->num_init_data ; i++) { + enum max77693_irq_source irq_src + = MAX77693_IRQ_GROUP_NR; + + max77693_write_reg(info->max77693->regmap_muic, + muic_pdata->init_data[i].addr, + muic_pdata->init_data[i].data); + + switch (muic_pdata->init_data[i].addr) { + case MAX77693_MUIC_REG_INTMASK1: + irq_src = MUIC_INT1; + break; + case MAX77693_MUIC_REG_INTMASK2: + irq_src = MUIC_INT2; + break; + case MAX77693_MUIC_REG_INTMASK3: + irq_src = MUIC_INT3; + break; + } + + if (irq_src < MAX77693_IRQ_GROUP_NR) + info->max77693->irq_masks_cur[irq_src] + = muic_pdata->init_data[i].data; } - if (irq_src < MAX77693_IRQ_GROUP_NR) - info->max77693->irq_masks_cur[irq_src] - = muic_pdata->init_data[i].data; - } + /* + * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB + * h/w path of COMP2/COMN1 on CONTROL1 register. + */ + if (muic_pdata->path_uart) + info->path_uart = muic_pdata->path_uart; + else + info->path_uart = CONTROL1_SW_UART; - /* - * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB - * h/w path of COMP2/COMN1 on CONTROL1 register. - */ - if (muic_pdata->path_uart) - info->path_uart = muic_pdata->path_uart; - else - info->path_uart = CONTROL1_SW_UART; + if (muic_pdata->path_usb) + info->path_usb = muic_pdata->path_usb; + else + info->path_usb = CONTROL1_SW_USB; - if (muic_pdata->path_usb) - info->path_usb = muic_pdata->path_usb; - else + /* + * Default delay time for detecting cable state + * after certain time. + */ + if (muic_pdata->detcable_delay_ms) + delay_jiffies = + msecs_to_jiffies(muic_pdata->detcable_delay_ms); + else + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } else { info->path_usb = CONTROL1_SW_USB; + info->path_uart = CONTROL1_SW_UART; + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } /* Set initial path for UART */ max77693_muic_set_path(info, info->path_uart, true); @@ -1208,10 +1226,6 @@ static int max77693_muic_probe(struct platform_device *pdev) * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq); - if (muic_pdata->detcable_delay_ms) - delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); - else - delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); schedule_delayed_work(&info->wq_detcable, delay_jiffies); return ret; -- cgit v1.2.3 From 0ec83bd2460ed6aed0e7f29f9e0633b054621c02 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 13 Mar 2013 17:38:57 +0900 Subject: extcon: max77693: Initialize register of MUIC device to bring up it without platform data This patch set default value of MUIC register to bring up MUIC device. If user don't set some initial value for MUIC device through platform data, extcon-max77693 driver use 'default_init_data' to bring up base operation of MAX77693 MUIC device. Signed-off-by: Chanwoo Choi Signed-off-by: Myungjoo Ham --- drivers/extcon/extcon-max77693.c | 93 ++++++++++++++++++++++++++---------- include/linux/mfd/max77693-private.h | 23 +++++++++ 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index fea10624f3e5..8f3c947b0029 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -32,6 +32,38 @@ #define DEV_NAME "max77693-muic" #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */ +/* + * Default value of MAX77693 register to bring up MUIC device. + * If user don't set some initial value for MUIC device through platform data, + * extcon-max77693 driver use 'default_init_data' to bring up base operation + * of MAX77693 MUIC device. + */ +struct max77693_reg_data default_init_data[] = { + { + /* STATUS2 - [3]ChgDetRun */ + .addr = MAX77693_MUIC_REG_STATUS2, + .data = STATUS2_CHGDETRUN_MASK, + }, { + /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */ + .addr = MAX77693_MUIC_REG_INTMASK1, + .data = INTMASK1_ADC1K_MASK + | INTMASK1_ADC_MASK, + }, { + /* INTMASK2 - Unmask [0]ChgTypM */ + .addr = MAX77693_MUIC_REG_INTMASK2, + .data = INTMASK2_CHGTYP_MASK, + }, { + /* INTMASK3 - Mask all of interrupts */ + .addr = MAX77693_MUIC_REG_INTMASK3, + .data = 0x0, + }, { + /* CDETCTRL2 */ + .addr = MAX77693_MUIC_REG_CDETCTRL2, + .data = CDETCTRL2_VIDRMEN_MASK + | CDETCTRL2_DXOVPEN_MASK, + }, +}; + enum max77693_muic_adc_debounce_time { ADC_DEBOUNCE_TIME_5MS = 0, ADC_DEBOUNCE_TIME_10MS, @@ -1046,6 +1078,8 @@ static int max77693_muic_probe(struct platform_device *pdev) struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); struct max77693_muic_info *info; + struct max77693_reg_data *init_data; + int num_init_data; int delay_jiffies; int ret; int i; @@ -1144,35 +1178,44 @@ static int max77693_muic_probe(struct platform_device *pdev) goto err_irq; } + + /* Initialize MUIC register by using platform data or default data */ if (pdata->muic_data) { - struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; + init_data = pdata->muic_data->init_data; + num_init_data = pdata->muic_data->num_init_data; + } else { + init_data = default_init_data; + num_init_data = ARRAY_SIZE(default_init_data); + } + + for (i = 0 ; i < num_init_data ; i++) { + enum max77693_irq_source irq_src + = MAX77693_IRQ_GROUP_NR; - /* Initialize MUIC register by using platform data */ - for (i = 0 ; i < muic_pdata->num_init_data ; i++) { - enum max77693_irq_source irq_src - = MAX77693_IRQ_GROUP_NR; - - max77693_write_reg(info->max77693->regmap_muic, - muic_pdata->init_data[i].addr, - muic_pdata->init_data[i].data); - - switch (muic_pdata->init_data[i].addr) { - case MAX77693_MUIC_REG_INTMASK1: - irq_src = MUIC_INT1; - break; - case MAX77693_MUIC_REG_INTMASK2: - irq_src = MUIC_INT2; - break; - case MAX77693_MUIC_REG_INTMASK3: - irq_src = MUIC_INT3; - break; - } - - if (irq_src < MAX77693_IRQ_GROUP_NR) - info->max77693->irq_masks_cur[irq_src] - = muic_pdata->init_data[i].data; + max77693_write_reg(info->max77693->regmap_muic, + init_data[i].addr, + init_data[i].data); + + switch (init_data[i].addr) { + case MAX77693_MUIC_REG_INTMASK1: + irq_src = MUIC_INT1; + break; + case MAX77693_MUIC_REG_INTMASK2: + irq_src = MUIC_INT2; + break; + case MAX77693_MUIC_REG_INTMASK3: + irq_src = MUIC_INT3; + break; } + if (irq_src < MAX77693_IRQ_GROUP_NR) + info->max77693->irq_masks_cur[irq_src] + = init_data[i].data; + } + + if (pdata->muic_data) { + struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; + /* * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB * h/w path of COMP2/COMN1 on CONTROL1 register. diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index 5b18ecde69b5..1aa4f13cdfa6 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -106,6 +106,29 @@ enum max77693_muic_reg { MAX77693_MUIC_REG_END, }; +/* MAX77693 INTMASK1~2 Register */ +#define INTMASK1_ADC1K_SHIFT 3 +#define INTMASK1_ADCERR_SHIFT 2 +#define INTMASK1_ADCLOW_SHIFT 1 +#define INTMASK1_ADC_SHIFT 0 +#define INTMASK1_ADC1K_MASK (1 << INTMASK1_ADC1K_SHIFT) +#define INTMASK1_ADCERR_MASK (1 << INTMASK1_ADCERR_SHIFT) +#define INTMASK1_ADCLOW_MASK (1 << INTMASK1_ADCLOW_SHIFT) +#define INTMASK1_ADC_MASK (1 << INTMASK1_ADC_SHIFT) + +#define INTMASK2_VIDRM_SHIFT 5 +#define INTMASK2_VBVOLT_SHIFT 4 +#define INTMASK2_DXOVP_SHIFT 3 +#define INTMASK2_DCDTMR_SHIFT 2 +#define INTMASK2_CHGDETRUN_SHIFT 1 +#define INTMASK2_CHGTYP_SHIFT 0 +#define INTMASK2_VIDRM_MASK (1 << INTMASK2_VIDRM_SHIFT) +#define INTMASK2_VBVOLT_MASK (1 << INTMASK2_VBVOLT_SHIFT) +#define INTMASK2_DXOVP_MASK (1 << INTMASK2_DXOVP_SHIFT) +#define INTMASK2_DCDTMR_MASK (1 << INTMASK2_DCDTMR_SHIFT) +#define INTMASK2_CHGDETRUN_MASK (1 << INTMASK2_CHGDETRUN_SHIFT) +#define INTMASK2_CHGTYP_MASK (1 << INTMASK2_CHGTYP_SHIFT) + /* MAX77693 MUIC - STATUS1~3 Register */ #define STATUS1_ADC_SHIFT (0) #define STATUS1_ADCLOW_SHIFT (5) -- cgit v1.2.3 From 13872ebb915b547b3c0a1fc04f549a1475bb7989 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 13 Mar 2013 04:10:57 -0600 Subject: ARM: OMAP1: fix USB host on 1710 There is a long-standing bug that OHCI USB host controller does not respond on 1710, because of wrong clock definitions. See e.g. http://marc.info/?l=linux-omap&m=119634441229321&w=2. All register reads return just zeroes: [ 1.896606] ohci ohci: OMAP OHCI [ 1.912597] ohci ohci: new USB bus registered, assigned bus number 1 [ 1.933776] ohci ohci: irq 38, io mem 0xfffba000 [ 2.012573] ohci ohci: init err (00000000 0000) [ 2.030334] ohci ohci: can't start [ 2.046661] ohci ohci: startup error -75 [ 2.063201] ohci ohci: USB bus 1 deregistered After some experiments, it seems that when changing the usb_dc_ck / SOFT_REQ enable bit from USB_REQ_EN_SHIFT to SOFT_USB_OTG_DPLL_REQ_SHIFT (like done also on 7XX), the USB appears to work: [ 2.183959] ohci ohci: OMAP OHCI [ 2.198242] ohci ohci: new USB bus registered, assigned bus number 1 [ 2.215820] ohci ohci: irq 38, io mem 0xfffba000 [ 2.324798] hub 1-0:1.0: USB hub found [ 2.361267] hub 1-0:1.0: 3 ports detected The patch is tested on Nokia 770. Signed-off-by: Aaro Koskinen Signed-off-by: Paul Walmsley --- arch/arm/mach-omap1/clock_data.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c index cb7c6ae2e3fc..6c4f766365a2 100644 --- a/arch/arm/mach-omap1/clock_data.c +++ b/arch/arm/mach-omap1/clock_data.c @@ -538,15 +538,6 @@ static struct clk usb_hhc_ck16xx = { }; static struct clk usb_dc_ck = { - .name = "usb_dc_ck", - .ops = &clkops_generic, - /* Direct from ULPD, no parent */ - .rate = 48000000, - .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG), - .enable_bit = USB_REQ_EN_SHIFT, -}; - -static struct clk usb_dc_ck7xx = { .name = "usb_dc_ck", .ops = &clkops_generic, /* Direct from ULPD, no parent */ @@ -727,8 +718,7 @@ static struct omap_clk omap_clks[] = { CLK(NULL, "usb_clko", &usb_clko, CK_16XX | CK_1510 | CK_310), CLK(NULL, "usb_hhc_ck", &usb_hhc_ck1510, CK_1510 | CK_310), CLK(NULL, "usb_hhc_ck", &usb_hhc_ck16xx, CK_16XX), - CLK(NULL, "usb_dc_ck", &usb_dc_ck, CK_16XX), - CLK(NULL, "usb_dc_ck", &usb_dc_ck7xx, CK_7XX), + CLK(NULL, "usb_dc_ck", &usb_dc_ck, CK_16XX | CK_7XX), CLK(NULL, "mclk", &mclk_1510, CK_1510 | CK_310), CLK(NULL, "mclk", &mclk_16xx, CK_16XX), CLK(NULL, "bclk", &bclk_1510, CK_1510 | CK_310), -- cgit v1.2.3 From 71b37071f02e20345dcc0d570c69896da795e1e6 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 13 Mar 2013 04:11:23 -0600 Subject: ARM: OMAP4: clock data: lock USB DPLL on boot Some versions of the u-boot bootloader do not lock the USB DPLL and when the USB DPLL is not locked, then it is observed that the L3INIT power domain does not transition to retention state during kernel suspend on OMAP4 devices. Fix this by locking the USB DPLL at 960 MHz on kernel boot. Signed-off-by: Jon Hunter Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cclock44xx_data.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index 3d58f335f173..015bcdc34b4a 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -52,6 +52,13 @@ */ #define OMAP4_DPLL_ABE_DEFFREQ 98304000 +/* + * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section + * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred + * locked frequency for the USB DPLL is 960MHz. + */ +#define OMAP4_DPLL_USB_DEFFREQ 960000000 + /* Root clocks */ DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0); @@ -1705,5 +1712,13 @@ int __init omap4xxx_clk_init(void) if (rc) pr_err("%s: failed to configure ABE DPLL!\n", __func__); + /* + * Lock USB DPLL on OMAP4 devices so that the L3INIT power + * domain can transition to retention state when not in use. + */ + rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + return 0; } -- cgit v1.2.3 From 092bc089c249de0fa0f0c98b28dea6e5f1367b6e Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Mon, 11 Mar 2013 21:49:00 +0200 Subject: ARM: OMAP3: hwmod data: keep MIDLEMODE in force-standby for musb For some unknown reason, allowing hwmod to control MIDLEMODE causes core_pwrdm to not hit idle states for musb in DM3730 at least. I've verified that setting any MIDLEMODE value other than "force standby" before enabling the device causes subsequent suspend attempts to fail with core_pwrdm not entering idle states, even if the driver is unloaded and "force standby" is restored before suspend attempt. To recover from this, soft reset can be used, but that's not suitable solution for suspend. Keeping the register set at force standby (reset value) makes it work and device still functions properly, as musb has driver-controlled OTG_FORCESTDBY register that controls MSTANDBY signal. Note that TI PSP kernels also have similar workarounds. This patch also fixes HWMOD_SWSUP_MSTANDBY documentation to match the actual flag name. Signed-off-by: Grazvydas Ignotas Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 7 +++++-- arch/arm/mach-omap2/omap_hwmod.h | 9 +++++++-- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 7 ++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index c2c798c08c2b..a202a4785104 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1368,7 +1368,9 @@ static void _enable_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + if (oh->flags & HWMOD_FORCE_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_FORCE; + } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) { idlemode = HWMOD_IDLEMODE_NO; } else { if (sf & SYSC_HAS_ENAWAKEUP) @@ -1440,7 +1442,8 @@ static void _idle_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + if ((oh->flags & HWMOD_SWSUP_MSTANDBY) || + (oh->flags & HWMOD_FORCE_MSTANDBY)) { idlemode = HWMOD_IDLEMODE_FORCE; } else { if (sf & SYSC_HAS_ENAWAKEUP) diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index d43d9b608eda..d5dc935f6060 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -427,8 +427,8 @@ struct omap_hwmod_omap4_prcm { * * HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out * of idle, rather than relying on module smart-idle - * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out - * of standby, rather than relying on module smart-standby + * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and + * out of standby, rather than relying on module smart-standby * HWMOD_INIT_NO_RESET: don't reset this module at boot - important for * SDRAM controller, etc. XXX probably belongs outside the main hwmod file * XXX Should be HWMOD_SETUP_NO_RESET @@ -459,6 +459,10 @@ struct omap_hwmod_omap4_prcm { * correctly, or this is being abused to deal with some PM latency * issues -- but we're currently suffering from a shortage of * folks who are able to track these issues down properly. + * HWMOD_FORCE_MSTANDBY: Always keep MIDLEMODE bits cleared so that device + * is kept in force-standby mode. Failing to do so causes PM problems + * with musb on OMAP3630 at least. Note that musb has a dedicated register + * to control MSTANDBY signal when MIDLEMODE is set to force-standby. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -471,6 +475,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_16BIT_REG (1 << 8) #define HWMOD_EXT_OPT_MAIN_CLK (1 << 9) #define HWMOD_BLOCK_WFI (1 << 10) +#define HWMOD_FORCE_MSTANDBY (1 << 11) /* * omap_hwmod._int_flags definitions diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index ac7e03ec952f..5112d04e7b79 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1707,9 +1707,14 @@ static struct omap_hwmod omap3xxx_usbhsotg_hwmod = { * Erratum ID: i479 idle_req / idle_ack mechanism potentially * broken when autoidle is enabled * workaround is to disable the autoidle bit at module level. + * + * Enabling the device in any other MIDLEMODE setting but force-idle + * causes core_pwrdm not enter idle states at least on OMAP3630. + * Note that musb has OTG_FORCESTDBY register that controls MSTANDBY + * signal when MIDLEMODE is set to force-idle. */ .flags = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE - | HWMOD_SWSUP_MSTANDBY, + | HWMOD_FORCE_MSTANDBY, }; /* usb_otg_hs */ -- cgit v1.2.3 From ec20fba77df4053ef703900be882527b95606592 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 12 Mar 2013 23:09:35 +0100 Subject: ASoC: samsung: remove last traces of neo1973-gta01 The support for the Openmoko Neo1973 GTA01 got removed in commit 1ae5cbc52e7c6619a3f44b87809fd25370df31bb ("ASoC: neo1973_wm8753: remove references to the neo1973-gta01 machine"). Remove its last traces in the Kconfig file too. Signed-off-by: Paul Bolle Acked-by: Kukjin Kim Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 90e7e6653233..475fb0d8b3c6 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -35,11 +35,10 @@ config SND_SAMSUNG_I2S tristate config SND_SOC_SAMSUNG_NEO1973_WM8753 - tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)" - depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02) + tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)" + depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02 select SND_S3C24XX_I2S select SND_SOC_WM8753 - select SND_SOC_LM4857 if MACH_NEO1973_GTA01 select SND_SOC_DFBMCS320 help Say Y here to enable audio support for the Openmoko Neo1973 -- cgit v1.2.3 From 92702df3570e1ccfa050e135e50c450502251b79 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 12 Feb 2013 20:28:12 +0000 Subject: ARM: OMAP4: PM: fix PM regression introduced by recent clock cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 17b7e7d33530e2bbd3bdc90f4db09b91cfdde2bb ("ARM: OMAP4: clock/hwmod data: start to remove some IP block control "clocks"") introduced a regression preventing the L3INIT clockdomain of OMAP4 systems from entering idle. This in turn prevented these systems from entering full chip clock-stop. The regression was caused by the incorrect removal of a so-called "optional functional clock" from the OMAP4 clock data. This wasn't caught for two reasons. First, I missed the retention entry failure in the branch test logs: http://www.pwsan.com/omap/testlogs/cleanup_a_3.9/20130126014242/pm/4460pandaes/4460pandaes_log.txt Second, the integration data for the OCP2SCP PHY IP block, added by commit 0c6688753f9912c6a7013549ec31c8844020bbc1 ("ARM: OMAP4: hwmod data: add remaining USB-related IP blocks"), should have associated this clock with the IP block, but did not. Fix by adding back the so-called "optional" functional clock to the clock data, and by linking that clock to the OCP2SCP PHY IP block integration hwmod data. The problem patch was discovered by J, Keerthy . Cc: Keerthy Cc: Benoît Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cclock44xx_data.c | 5 +++++ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index 015bcdc34b4a..0c6834ae1fc4 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -1018,6 +1018,10 @@ DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); +DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0, + OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, + OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL); + DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); @@ -1545,6 +1549,7 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk, CK_443X), CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk, CK_443X), CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk, CK_443X), + CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X), CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X), CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X), CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X), diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 0e47d2e1687c..9e0576569e07 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2714,6 +2714,10 @@ static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = { { } }; +static struct omap_hwmod_opt_clk ocp2scp_usb_phy_opt_clks[] = { + { .role = "48mhz", .clk = "ocp2scp_usb_phy_phy_48m" }, +}; + /* ocp2scp_usb_phy */ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { .name = "ocp2scp_usb_phy", @@ -2728,6 +2732,8 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { }, }, .dev_attr = ocp2scp_dev_attr, + .opt_clks = ocp2scp_usb_phy_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(ocp2scp_usb_phy_opt_clks), }; /* -- cgit v1.2.3 From 77c641d3468a66377752ee9ae06e65dee41fe804 Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Mon, 11 Mar 2013 17:58:57 +0200 Subject: ASoC: omap: convert to devm_ioremap_resource() Convert all uses of devm_request_and_ioremap() to the newly introduced devm_ioremap_resource() which provides more consistent error handling. devm_ioremap_resource() provides its own error messages so all explicit error messages can be removed from the failure code paths. Signed-off-by: Silviu-Mihai Popescu Acked-by: Jarkko Nikula Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-dmic.c | 9 +++------ sound/soc/omap/omap-mcpdm.c | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 77e9e7e68edc..8ebaf117d81f 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -493,12 +493,9 @@ static int asoc_dmic_probe(struct platform_device *pdev) goto err_put_clk; } - dmic->io_base = devm_request_and_ioremap(&pdev->dev, res); - if (!dmic->io_base) { - dev_err(&pdev->dev, "cannot remap\n"); - ret = -ENOMEM; - goto err_put_clk; - } + dmic->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dmic->io_base)) + return PTR_ERR(dmic->io_base); ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai); if (ret) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 079f277cdba4..ddfcc1834ff0 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -464,11 +464,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) if (res == NULL) return -ENOMEM; - mcpdm->io_base = devm_request_and_ioremap(&pdev->dev, res); - if (!mcpdm->io_base) { - dev_err(&pdev->dev, "cannot remap\n"); - return -ENOMEM; - } + mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mcpdm->io_base)) + return PTR_ERR(mcpdm->io_base); mcpdm->irq = platform_get_irq(pdev, 0); if (mcpdm->irq < 0) -- cgit v1.2.3 From 127c5cad87099fef816c8597258fc06285d17bb1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 12 Mar 2013 20:51:28 -0300 Subject: ASoC: fsl: imx-audmux: Use devm_clk_get() By using devm_clk_get() we can save a call to clk_put(). Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 3f333e5b4673..47f046a8fdab 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -262,7 +262,7 @@ static int imx_audmux_probe(struct platform_device *pdev) return PTR_ERR(pinctrl); } - audmux_clk = clk_get(&pdev->dev, "audmux"); + audmux_clk = devm_clk_get(&pdev->dev, "audmux"); if (IS_ERR(audmux_clk)) { dev_dbg(&pdev->dev, "cannot get clock: %ld\n", PTR_ERR(audmux_clk)); @@ -282,7 +282,6 @@ static int imx_audmux_remove(struct platform_device *pdev) { if (audmux_type == IMX31_AUDMUX) audmux_debugfs_remove(); - clk_put(audmux_clk); return 0; } -- cgit v1.2.3 From 9c3372898323cb9596a23097e939df3bd83de5fc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 12 Mar 2013 17:41:54 -0700 Subject: ASoC: fsi: remove unused irq FSI is using devm_request_irq() from 1ddd82868cc888e008ed520465c172a6cdddd689 (ASoC: fsi: use devm_request_irq()) master->irq is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c724026a246f..8b91a15110e0 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -296,7 +296,6 @@ struct fsi_core { struct fsi_master { void __iomem *base; - int irq; struct fsi_priv fsia; struct fsi_priv fsib; const struct fsi_core *core; @@ -2002,7 +2001,6 @@ static int fsi_probe(struct platform_device *pdev) } /* master setting */ - master->irq = irq; master->core = core; spin_lock_init(&master->lock); -- cgit v1.2.3 From 030e79f658de11da43d32e7ad814b5d2d64c8bac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 11 Mar 2013 18:27:21 -0700 Subject: ASoC: add snd_soc_register_component() Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. As result of ASoC community discussion, we consider new struct snd_soc_component for CPU/CODEC, and will switch over to use it. This patch adds very basic struct snd_soc_component, and register function for it. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Reviewed-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/soc.h | 19 +++++++++++++ sound/soc/soc-core.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index a6a059ca3874..8c46d0a7e2c0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -324,6 +324,8 @@ struct snd_soc_dai_link; struct snd_soc_platform_driver; struct snd_soc_codec; struct snd_soc_codec_driver; +struct snd_soc_component; +struct snd_soc_component_driver; struct soc_enum; struct snd_soc_jack; struct snd_soc_jack_zone; @@ -377,6 +379,10 @@ int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_codec(struct device *dev); +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); +void snd_soc_unregister_component(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_codec_readable_register(struct snd_soc_codec *codec, @@ -841,6 +847,19 @@ struct snd_soc_platform { #endif }; +struct snd_soc_component_driver { +}; + +struct snd_soc_component { + const char *name; + int id; + int num_dai; + struct device *dev; + struct list_head list; + + const struct snd_soc_component_driver *driver; +}; + struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b7e84a7cd9ee..9e6118573fef 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); +static LIST_HEAD(component_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -4137,6 +4138,82 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + +/** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->num_dai = num_dai; + + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ + struct snd_soc_component *cmpnt; + + list_for_each_entry(cmpnt, &component_list, list) { + if (dev == cmpnt->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} + /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) -- cgit v1.2.3 From 28dbd1611f5701c9b5b8c07924c1bd2ad6f64435 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Mar 2013 08:32:53 +0300 Subject: ASoC: tas5086: signedness bug in tas5086_hw_params() "val" has to be signed for the error handling to work. Signed-off-by: Dan Carpenter Acked-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tas5086.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 40cee844f0cf..d447c4aa1d5e 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -251,7 +251,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); - unsigned int val; + int val; int ret; priv->rate = params_rate(params); -- cgit v1.2.3 From 3f341f741de956980775761370e3abc4122be53a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 8 Mar 2013 15:22:29 +0800 Subject: ASoC: arizona: Provide defines for the clock rates Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 12 ++++++------ sound/soc/codecs/arizona.h | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ad21d8255341..0c70d503fd32 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -504,27 +504,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, break; case 11289600: case 12288000: - val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 22579200: case 24576000: - val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 45158400: case 49152000: - val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 67737600: case 73728000: - val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 90316800: case 98304000: - val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 135475200: case 147456000: - val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT; + val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT; break; case 0: dev_dbg(arizona->dev, "%s cleared\n", name); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index d592adcc969c..572f11bc90b4 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -49,6 +49,14 @@ #define ARIZONA_MIXER_VOL_SHIFT 1 #define ARIZONA_MIXER_VOL_WIDTH 7 +#define ARIZONA_CLK_6MHZ 0 +#define ARIZONA_CLK_12MHZ 1 +#define ARIZONA_CLK_24MHZ 2 +#define ARIZONA_CLK_49MHZ 3 +#define ARIZONA_CLK_73MHZ 4 +#define ARIZONA_CLK_98MHZ 5 +#define ARIZONA_CLK_147MHZ 6 + #define ARIZONA_MAX_DAI 4 #define ARIZONA_MAX_ADSP 4 -- cgit v1.2.3 From f395a21853935ab7a2d0d760cda206ae55300194 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 22:39:54 +0800 Subject: ASoC: wm_adsp: Handle old .bin files Older .bin files report the global coefficients as absolute address writes to zero; maintain compatibility with them. Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 26 ++++++++++++++++++++++---- sound/soc/codecs/wm_adsp.h | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f3f7e75f8628..febb4c76535e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -549,8 +549,9 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) buf_size = sizeof(adsp1_id); algs = be32_to_cpu(adsp1_id.algs); + dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp1_id.fw.id), + dsp->fw_id, (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, be32_to_cpu(adsp1_id.fw.ver) & 0xff, @@ -573,8 +574,9 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) buf_size = sizeof(adsp2_id); algs = be32_to_cpu(adsp2_id.algs); + dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", - be32_to_cpu(adsp2_id.fw.id), + dsp->fw_id, (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, be32_to_cpu(adsp2_id.fw.ver) & 0xff, @@ -781,8 +783,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) case (WMFW_INFO_TEXT << 8): break; case (WMFW_ABSOLUTE << 8): - region_name = "register"; - reg = offset; + /* + * Old files may use this for global + * coefficients. + */ + if (le32_to_cpu(blk->id) == dsp->fw_id && + offset == 0) { + region_name = "global coefficients"; + mem = wm_adsp_find_region(dsp, type); + if (!mem) { + adsp_err(dsp, "No ZM\n"); + break; + } + reg = wm_adsp_region_to_reg(mem, 0); + + } else { + region_name = "register"; + reg = offset; + } break; case WMFW_ADSP1_DM: diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index cb8871a3ec00..d6fd8af53b5d 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -46,6 +46,8 @@ struct wm_adsp { struct list_head alg_regions; + int fw_id; + const struct wm_adsp_region *mem; int num_mems; -- cgit v1.2.3 From 6a40cdd5440d7b61a349bc04e85eed4fa7c24a3c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 5 Mar 2013 14:58:53 +0800 Subject: pinctrl: abx500: Fix checking if pin use AlternateFunction register It's pointless to check "af.alt_bit1 == UNUSED" twice. This looks like a copy-paste bug, I think what we want is to check if *both* af.alt_bit1 and af.alt_bit2 are UNUSED. Signed-off-by: Axel Lin Acked-by: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-abx500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c index caecdd373061..c542a97c82f3 100644 --- a/drivers/pinctrl/pinctrl-abx500.c +++ b/drivers/pinctrl/pinctrl-abx500.c @@ -422,7 +422,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, } /* check if pin use AlternateFunction register */ - if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED)) + if ((af.alt_bit1 == UNUSED) && (af.alt_bit2 == UNUSED)) return mode; /* * if pin GPIOSEL bit is set and pin supports alternate function, -- cgit v1.2.3 From 53ded8191e81507da0786ac45152eebb68d25d0c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Mar 2013 03:18:18 +0100 Subject: pinctrl: Print the correct information in debugfs pinconf-state file A bad copy&paste resulted in the debugfs pinconf-state file printing the pin name instead of the state name. Fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index ac8d382a79bb..d611ecfcbf70 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -622,7 +622,7 @@ static const struct file_operations pinconf_dbg_pinname_fops = { static int pinconf_dbg_state_print(struct seq_file *s, void *d) { if (strlen(dbg_state_name)) - seq_printf(s, "%s\n", dbg_pinname); + seq_printf(s, "%s\n", dbg_state_name); else seq_printf(s, "No pin state set\n"); return 0; -- cgit v1.2.3 From bf4d7be57ba9040347065f48a60f895a254f6e28 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 13 Mar 2013 17:13:46 +0530 Subject: pinctrl: generic: Fix compilation error The function definition of pinconf_generic_dump_config is defined under CONFIG_DEBUG_FS macro. Define the declaration too under this macro. Without this patch we get the following build error: drivers/built-in.o: In function `pcs_pinconf_config_dbg_show': drivers/pinctrl/pinctrl-single.c:726: undefined reference to `pinconf_generic_dump_config' Signed-off-by: Sachin Kamat Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index e3ed8cb072a5..bfda73d64eed 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -90,7 +90,7 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot, * pin config. */ -#ifdef CONFIG_GENERIC_PINCONF +#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS) void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin); -- cgit v1.2.3 From 76bf969e6f86e5de788dd943ff2d4340bac71822 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Mar 2013 14:17:47 +0800 Subject: ASoC: arizona: Ensure we clock two channels for I2S mode I2S requires stereo clocking even for mono data. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c70d503fd32..2b0803ec8234 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -818,7 +818,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, struct arizona *arizona = priv->arizona; int base = dai->driver->base; const int *rates; - int i, ret; + int i, ret, val; int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; int bclk, lrclk, wl, frame, bclk_target; @@ -834,6 +834,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, bclk_target *= chan_limit; } + /* Force stereo for I2S mode */ + val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); + if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { + arizona_aif_dbg(dai, "Forcing stereo mode\n"); + bclk_target *= 2; + } + for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { if (rates[i] >= bclk_target && rates[i] % params_rate(params) == 0) { -- cgit v1.2.3 From 8abac3ba51b5525354e9b2ec0eed1c9e95c905d9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 13 Mar 2013 16:38:33 +0100 Subject: regmap: cache Fix regcache-rbtree sync The last register block, which falls into the specified range, is not handled correctly. The formula which calculates the number of register which should be synced is inverse (and off by one). E.g. if all registers in that block should be synced only one is synced, and if only one should be synced all (but one) are synced. To calculate the number of registers that need to be synced we need to subtract the number of the first register in the block from the max register number and add one. This patch updates the code accordingly. The issue was introduced in commit ac8d91c ("regmap: Supply ranges to the sync operations"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/base/regmap/regcache-rbtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index e6732cf7c06e..79f4fca9877a 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -398,7 +398,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, base = 0; if (max < rbnode->base_reg + rbnode->blklen) - end = rbnode->base_reg + rbnode->blklen - max; + end = max - rbnode->base_reg + 1; else end = rbnode->blklen; -- cgit v1.2.3 From a4285b99e0087361c61f51c819633382fa659ea6 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 13 Mar 2013 20:54:34 +0100 Subject: MIPS: Fix inconsistent formatting inside /proc/cpuinfo There is a missing " " inside /proc/cpuinfo. The bad commit was: commit a96102be700f87283f168942cd09a2b30f86f324 Author: Steven J. Hill Date: Fri Dec 7 04:31:36 2012 +0000 MIPS: Add printing of ISA version in cpuinfo. Signed-off-by: John Crispin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/4988/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 135c4aadccbe..7a54f74b7818 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -67,7 +67,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_mips_r) { seq_printf(m, "isa\t\t\t:"); if (cpu_has_mips_1) - seq_printf(m, "%s", "mips1"); + seq_printf(m, "%s", " mips1"); if (cpu_has_mips_2) seq_printf(m, "%s", " mips2"); if (cpu_has_mips_3) -- cgit v1.2.3 From 67e753ca41782913d805ff4a8a2b0f60b26b7915 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 14 Mar 2013 10:49:23 +0200 Subject: UBIFS: make space fixup work in the remount case The UBIFS space fixup is a useful feature which allows to fixup the "broken" flash space at the time of the first mount. The "broken" space is usually the result of using a "dumb" industrial flasher which is not able to skip empty NAND pages and just writes all 0xFFs to the empty space, which has grave side-effects for UBIFS when UBIFS trise to write useful data to those empty pages. The fix-up feature works roughly like this: 1. mkfs.ubifs sets the fixup flag in UBIFS superblock when creating the image (see -F option) 2. when the file-system is mounted for the first time, UBIFS notices the fixup flag and re-writes the entire media atomically, which may take really a lot of time. 3. UBIFS clears the fixup flag in the superblock. This works fine when the file system is mounted R/W for the very first time. But it did not really work in the case when we first mount the file-system R/O, and then re-mount R/W. The reason was that we started the fixup procedure too late, which we cannot really do because we have to fixup the space before it starts being used. Signed-off-by: Artem Bityutskiy Reported-by: Mark Jackson Cc: stable@vger.kernel.org # 3.0+ --- fs/ubifs/super.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index ac838b844936..f21acf0ef01f 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1568,6 +1568,12 @@ static int ubifs_remount_rw(struct ubifs_info *c) c->remounting_rw = 1; c->ro_mount = 0; + if (c->space_fixup) { + err = ubifs_fixup_free_space(c); + if (err) + return err; + } + err = check_free_space(c); if (err) goto out; @@ -1684,12 +1690,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) err = dbg_check_space_info(c); } - if (c->space_fixup) { - err = ubifs_fixup_free_space(c); - if (err) - goto out; - } - mutex_unlock(&c->umount_mutex); return err; -- cgit v1.2.3 From eb20ff9c91ddcb2d55c1849a87d3db85af5e88a9 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 13 Mar 2013 19:46:20 -0300 Subject: Bluetooth: Fix not closing SCO sockets in the BT_CONNECT2 state With deferred setup for SCO, it is possible that userspace closes the socket when it is in the BT_CONNECT2 state, after the Connect Request is received but before the Accept Synchonous Connection is sent. If this happens the following crash was observed, when the connection is terminated: [ +0.000003] hci_sync_conn_complete_evt: hci0 status 0x10 [ +0.000005] sco_connect_cfm: hcon ffff88003d1bd800 bdaddr 40:98:4e:32:d7:39 status 16 [ +0.000003] sco_conn_del: hcon ffff88003d1bd800 conn ffff88003cc8e300, err 110 [ +0.000015] BUG: unable to handle kernel NULL pointer dereference at 0000000000000199 [ +0.000906] IP: [] __lock_acquire+0xed/0xe82 [ +0.000000] PGD 3d21f067 PUD 3d291067 PMD 0 [ +0.000000] Oops: 0002 [#1] SMP [ +0.000000] Modules linked in: rfcomm bnep btusb bluetooth [ +0.000000] CPU 0 [ +0.000000] Pid: 1481, comm: kworker/u:2H Not tainted 3.9.0-rc1-25019-gad82cdd #1 Bochs Bochs [ +0.000000] RIP: 0010:[] [] __lock_acquire+0xed/0xe82 [ +0.000000] RSP: 0018:ffff88003c3c19d8 EFLAGS: 00010002 [ +0.000000] RAX: 0000000000000001 RBX: 0000000000000246 RCX: 0000000000000000 [ +0.000000] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88003d1be868 [ +0.000000] RBP: ffff88003c3c1a98 R08: 0000000000000002 R09: 0000000000000000 [ +0.000000] R10: ffff88003d1be868 R11: ffff88003e20b000 R12: 0000000000000002 [ +0.000000] R13: ffff88003aaa8000 R14: 000000000000006e R15: ffff88003d1be850 [ +0.000000] FS: 0000000000000000(0000) GS:ffff88003e200000(0000) knlGS:0000000000000000 [ +0.000000] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ +0.000000] CR2: 0000000000000199 CR3: 000000003c1cb000 CR4: 00000000000006b0 [ +0.000000] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ +0.000000] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ +0.000000] Process kworker/u:2H (pid: 1481, threadinfo ffff88003c3c0000, task ffff88003aaa8000) [ +0.000000] Stack: [ +0.000000] ffffffff81b16342 0000000000000000 0000000000000000 ffff88003d1be868 [ +0.000000] ffffffff00000000 00018c0c7863e367 000000003c3c1a28 ffffffff8101efbd [ +0.000000] 0000000000000000 ffff88003e3d2400 ffff88003c3c1a38 ffffffff81007c7a [ +0.000000] Call Trace: [ +0.000000] [] ? kvm_clock_read+0x34/0x3b [ +0.000000] [] ? paravirt_sched_clock+0x9/0xd [ +0.000000] [] ? sched_clock+0x9/0xb [ +0.000000] [] ? sched_clock_local+0x12/0x75 [ +0.000000] [] lock_acquire+0x93/0xb1 [ +0.000000] [] ? spin_lock+0x9/0xb [bluetooth] [ +0.000000] [] ? lock_release_holdtime.part.22+0x4e/0x55 [ +0.000000] [] _raw_spin_lock+0x40/0x74 [ +0.000000] [] ? spin_lock+0x9/0xb [bluetooth] [ +0.000000] [] ? _raw_spin_unlock+0x23/0x36 [ +0.000000] [] spin_lock+0x9/0xb [bluetooth] [ +0.000000] [] sco_conn_del+0x76/0xbb [bluetooth] [ +0.000000] [] sco_connect_cfm+0x2da/0x2e9 [bluetooth] [ +0.000000] [] hci_proto_connect_cfm+0x38/0x65 [bluetooth] [ +0.000000] [] hci_sync_conn_complete_evt.isra.79+0x11a/0x13e [bluetooth] [ +0.000000] [] hci_event_packet+0x153b/0x239d [bluetooth] [ +0.000000] [] ? _raw_spin_unlock_irqrestore+0x48/0x5c [ +0.000000] [] hci_rx_work+0xf3/0x2e3 [bluetooth] [ +0.000000] [] process_one_work+0x1dc/0x30b [ +0.000000] [] ? process_one_work+0x172/0x30b [ +0.000000] [] ? spin_lock_irq+0x9/0xb [ +0.000000] [] worker_thread+0x123/0x1d2 [ +0.000000] [] ? manage_workers+0x240/0x240 [ +0.000000] [] kthread+0x9d/0xa5 [ +0.000000] [] ? __kthread_parkme+0x60/0x60 [ +0.000000] [] ret_from_fork+0x7c/0xb0 [ +0.000000] [] ? __kthread_parkme+0x60/0x60 [ +0.000000] Code: d7 44 89 8d 50 ff ff ff 4c 89 95 58 ff ff ff e8 44 fc ff ff 44 8b 8d 50 ff ff ff 48 85 c0 4c 8b 95 58 ff ff ff 0f 84 7a 04 00 00 ff 80 98 01 00 00 83 3d 25 41 a7 00 00 45 8b b5 e8 05 00 00 [ +0.000000] RIP [] __lock_acquire+0xed/0xe82 [ +0.000000] RSP [ +0.000000] CR2: 0000000000000199 [ +0.000000] ---[ end trace e73cd3b52352dd34 ]--- Cc: stable@vger.kernel.org [3.8] Signed-off-by: Vinicius Costa Gomes Tested-by: Frederic Dalleau Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 57f250c20e39..aaf1957bc4fe 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -361,6 +361,7 @@ static void __sco_sock_close(struct sock *sk) sco_chan_del(sk, ECONNRESET); break; + case BT_CONNECT2: case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); -- cgit v1.2.3 From 1b1861ead4f9fd7314acb2a8950a2b75ad2c8af5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 7 Mar 2013 23:53:12 +0100 Subject: ASoC: cs4271: convert to direct regmap API usage By using the regmap API directly, we can make use of the .write_flag_mask for SPI, which allows us to drop the strange register hacks that were necessary so far. Signed-off-by: Daniel Mack Acked-by: Alexander Sverdlin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 159 ++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 2415a4118dbd..ac0d3b4844a8 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -39,17 +39,15 @@ /* * CS4271 registers - * High byte represents SPI chip address (0x10) + write command (0) - * Low byte - codec register address */ -#define CS4271_MODE1 0x2001 /* Mode Control 1 */ -#define CS4271_DACCTL 0x2002 /* DAC Control */ -#define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */ -#define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */ -#define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */ -#define CS4271_ADCCTL 0x2006 /* ADC Control */ -#define CS4271_MODE2 0x2007 /* Mode Control 2 */ -#define CS4271_CHIPID 0x2008 /* Chip ID */ +#define CS4271_MODE1 0x01 /* Mode Control 1 */ +#define CS4271_DACCTL 0x02 /* DAC Control */ +#define CS4271_DACVOL 0x03 /* DAC Volume & Mixing Control */ +#define CS4271_VOLA 0x04 /* DAC Channel A Volume Control */ +#define CS4271_VOLB 0x05 /* DAC Channel B Volume Control */ +#define CS4271_ADCCTL 0x06 /* ADC Control */ +#define CS4271_MODE2 0x07 /* Mode Control 2 */ +#define CS4271_CHIPID 0x08 /* Chip ID */ #define CS4271_FIRSTREG CS4271_MODE1 #define CS4271_LASTREG CS4271_MODE2 @@ -144,23 +142,27 @@ * Array do not include Chip ID, as codec driver does not use * registers read operations at all */ -static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = { - 0, - 0, - CS4271_DACCTL_AMUTE, - CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, - 0, - 0, - 0, - 0, +static const struct reg_default cs4271_reg_defaults[] = { + { CS4271_MODE1, 0, }, + { CS4271_DACCTL, CS4271_DACCTL_AMUTE, }, + { CS4271_DACVOL, CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, }, + { CS4271_VOLA, 0, }, + { CS4271_VOLB, 0, }, + { CS4271_ADCCTL, 0, }, + { CS4271_MODE2, 0, }, }; +static bool cs4271_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == CS4271_CHIPID; +} + struct cs4271_private { /* SND_SOC_I2C or SND_SOC_SPI */ - enum snd_soc_control_type bus_type; unsigned int mclk; bool master; bool deemph; + struct regmap *regmap; /* Current sample rate for de-emphasis control */ int rate; /* GPIO driving Reset pin, if any */ @@ -210,14 +212,14 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_LEFT_J: val |= CS4271_MODE1_DAC_DIF_LJ; - ret = snd_soc_update_bits(codec, CS4271_ADCCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL, CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ); if (ret < 0) return ret; break; case SND_SOC_DAIFMT_I2S: val |= CS4271_MODE1_DAC_DIF_I2S; - ret = snd_soc_update_bits(codec, CS4271_ADCCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL, CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S); if (ret < 0) return ret; @@ -227,7 +229,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - ret = snd_soc_update_bits(codec, CS4271_MODE1, + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1, CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val); if (ret < 0) return ret; @@ -252,7 +254,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec) val <<= 4; } - ret = snd_soc_update_bits(codec, CS4271_DACCTL, + ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL, CS4271_DACCTL_DEM_MASK, val); if (ret < 0) return ret; @@ -341,14 +343,14 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, !dai->capture_active) || (substream->stream == SNDRV_PCM_STREAM_CAPTURE && !dai->playback_active)) { - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, - CS4271_MODE2_PDN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, + CS4271_MODE2_PDN); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; } @@ -378,7 +380,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, val |= cs4271_clk_tab[i].ratio_mask; - ret = snd_soc_update_bits(codec, CS4271_MODE1, + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1, CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val); if (ret < 0) return ret; @@ -389,6 +391,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); int ret; int val_a = 0; int val_b = 0; @@ -398,10 +401,13 @@ static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) val_b = CS4271_VOLB_MUTE; } - ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a); + ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA, + CS4271_VOLA_MUTE, val_a); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b); + + ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB, + CS4271_VOLB_MUTE, val_b); if (ret < 0) return ret; @@ -463,25 +469,33 @@ static struct snd_soc_dai_driver cs4271_dai = { static int cs4271_soc_suspend(struct snd_soc_codec *codec) { int ret; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); + /* Set power-down bit */ - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, - CS4271_MODE2_PDN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, CS4271_MODE2_PDN); if (ret < 0) return ret; + return 0; } static int cs4271_soc_resume(struct snd_soc_codec *codec) { int ret; + struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); + /* Restore codec state */ - ret = snd_soc_cache_sync(codec); + ret = regcache_sync(cs4271->regmap); if (ret < 0) return ret; + /* then disable the power-down bit */ - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; + return 0; } #else @@ -542,40 +556,22 @@ static int cs4271_probe(struct snd_soc_codec *codec) cs4271->gpio_nreset = gpio_nreset; - /* - * In case of I2C, chip address specified in board data. - * So cache IO operations use 8 bit codec register address. - * In case of SPI, chip address and register address - * passed together as 16 bit value. - * Anyway, register address is masked with 0xFF inside - * soc-cache code. - */ - if (cs4271->bus_type == SND_SOC_SPI) - ret = snd_soc_codec_set_cache_io(codec, 16, 8, - cs4271->bus_type); - else - ret = snd_soc_codec_set_cache_io(codec, 8, 8, - cs4271->bus_type); - if (ret) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - ret = snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_PDN | CS4271_MODE2_CPEN, - CS4271_MODE2_PDN | CS4271_MODE2_CPEN); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN | CS4271_MODE2_CPEN, + CS4271_MODE2_PDN | CS4271_MODE2_CPEN); if (ret < 0) return ret; - ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); + ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_PDN, 0); if (ret < 0) return ret; /* Power-up sequence requires 85 uS */ udelay(85); if (amutec_eq_bmutec) - snd_soc_update_bits(codec, CS4271_MODE2, - CS4271_MODE2_MUTECAEQUB, - CS4271_MODE2_MUTECAEQUB); + regmap_update_bits(cs4271->regmap, CS4271_MODE2, + CS4271_MODE2_MUTECAEQUB, + CS4271_MODE2_MUTECAEQUB); return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); @@ -597,13 +593,24 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { .remove = cs4271_remove, .suspend = cs4271_soc_suspend, .resume = cs4271_soc_resume, - .reg_cache_default = cs4271_dflt_reg, - .reg_cache_size = ARRAY_SIZE(cs4271_dflt_reg), - .reg_word_size = sizeof(cs4271_dflt_reg[0]), - .compress_type = SND_SOC_FLAT_COMPRESSION, }; #if defined(CONFIG_SPI_MASTER) + +static const struct regmap_config cs4271_spi_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = CS4271_LASTREG, + .read_flag_mask = 0x21, + .write_flag_mask = 0x20, + + .reg_defaults = cs4271_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = cs4271_volatile_reg, +}; + static int cs4271_spi_probe(struct spi_device *spi) { struct cs4271_private *cs4271; @@ -613,7 +620,9 @@ static int cs4271_spi_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, cs4271); - cs4271->bus_type = SND_SOC_SPI; + cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); + if (IS_ERR(cs4271->regmap)) + return PTR_ERR(cs4271->regmap); return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, &cs4271_dai, 1); @@ -643,6 +652,18 @@ static const struct i2c_device_id cs4271_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); +static const struct regmap_config cs4271_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = CS4271_LASTREG, + + .reg_defaults = cs4271_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = cs4271_volatile_reg, +}; + static int cs4271_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -653,7 +674,9 @@ static int cs4271_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, cs4271); - cs4271->bus_type = SND_SOC_I2C; + cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); + if (IS_ERR(cs4271->regmap)) + return PTR_ERR(cs4271->regmap); return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, &cs4271_dai, 1); -- cgit v1.2.3 From 61782e4f5eb593958582524aad9b14dc98b1b56c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 14 Mar 2013 00:18:41 -0700 Subject: ASoC: add .name for snd_soc_component_driver This patch adds .name member on snd_soc_component_driver. But this patch doesn't care about whether cmpnt_drv was NULL, and/or its name was NULL in snd_soc_register_component() at this point. Because, it is easy to switch over to snd_soc_register_component() from snd_soc_register_dais() if it doesn't care cmpnt_drv was NULL. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8c46d0a7e2c0..44c9cbdc9fa2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -848,6 +848,7 @@ struct snd_soc_platform { }; struct snd_soc_component_driver { + const char *name; }; struct snd_soc_component { -- cgit v1.2.3 From da4f2f9e6b59d9236fec1d5cfc85dd3b5679d1b3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 14 Mar 2013 00:19:20 -0700 Subject: ASoC: fsi: use snd_soc_register_component() instead of snd_soc_register_dais() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c724026a246f..254c6375f7a1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1886,6 +1886,10 @@ static struct snd_soc_platform_driver fsi_soc_platform = { .pcm_free = fsi_pcm_free, }; +static const struct snd_soc_component_driver fsi_soc_component = { + .name = "fsi", +}; + /* * platform function */ @@ -2046,10 +2050,10 @@ static int fsi_probe(struct platform_device *pdev) goto exit_fsib; } - ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, - ARRAY_SIZE(fsi_soc_dai)); + ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component, + fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); if (ret < 0) { - dev_err(&pdev->dev, "cannot snd dai register\n"); + dev_err(&pdev->dev, "cannot snd component register\n"); goto exit_snd_soc; } @@ -2074,7 +2078,7 @@ static int fsi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); + snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); fsi_stream_remove(&master->fsia); -- cgit v1.2.3 From 0d98da5d845e0d0293055913ce65c9904b3b902a Mon Sep 17 00:00:00 2001 From: Gao feng Date: Thu, 7 Mar 2013 17:20:46 +0000 Subject: netfilter: nf_conntrack: register pernet subsystem before register L4 proto In (c296bb4 netfilter: nf_conntrack: refactor l4proto support for netns) the l4proto gre/dccp/udplite/sctp registration happened before the pernet subsystem, which is wrong. Register pernet subsystem before register L4proto since after register L4proto, init_conntrack may try to access the resources which allocated in register_pernet_subsys. Reported-by: Alexey Dobriyan Cc: Alexey Dobriyan Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_proto_dccp.c | 12 ++++++------ net/netfilter/nf_conntrack_proto_gre.c | 12 ++++++------ net/netfilter/nf_conntrack_proto_sctp.c | 12 ++++++------ net/netfilter/nf_conntrack_proto_udplite.c | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 432f95780003..ba65b2041eb4 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -969,6 +969,10 @@ static int __init nf_conntrack_proto_dccp_init(void) { int ret; + ret = register_pernet_subsys(&dccp_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&dccp_proto4); if (ret < 0) goto out_dccp4; @@ -977,16 +981,12 @@ static int __init nf_conntrack_proto_dccp_init(void) if (ret < 0) goto out_dccp6; - ret = register_pernet_subsys(&dccp_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&dccp_proto6); out_dccp6: nf_ct_l4proto_unregister(&dccp_proto4); out_dccp4: + unregister_pernet_subsys(&dccp_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index bd7d01d9c7e7..155ce9f8a0db 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -420,18 +420,18 @@ static int __init nf_ct_proto_gre_init(void) { int ret; - ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4); - if (ret < 0) - goto out_gre4; - ret = register_pernet_subsys(&proto_gre_net_ops); if (ret < 0) goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4); + if (ret < 0) + goto out_gre4; + return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); out_gre4: + unregister_pernet_subsys(&proto_gre_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 480f616d5936..ec83536def9a 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -888,6 +888,10 @@ static int __init nf_conntrack_proto_sctp_init(void) { int ret; + ret = register_pernet_subsys(&sctp_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp4); if (ret < 0) goto out_sctp4; @@ -896,16 +900,12 @@ static int __init nf_conntrack_proto_sctp_init(void) if (ret < 0) goto out_sctp6; - ret = register_pernet_subsys(&sctp_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6); out_sctp6: nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4); out_sctp4: + unregister_pernet_subsys(&sctp_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 157489581c31..ca969f6273f7 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -371,6 +371,10 @@ static int __init nf_conntrack_proto_udplite_init(void) { int ret; + ret = register_pernet_subsys(&udplite_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4); if (ret < 0) goto out_udplite4; @@ -379,16 +383,12 @@ static int __init nf_conntrack_proto_udplite_init(void) if (ret < 0) goto out_udplite6; - ret = register_pernet_subsys(&udplite_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6); out_udplite6: nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4); out_udplite4: + unregister_pernet_subsys(&udplite_net_ops); +out_pernet: return ret; } -- cgit v1.2.3 From bae99f7a1d372374aaf9ed8910f3b825da995b36 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 14 Mar 2013 06:03:18 +0000 Subject: netfilter: nfnetlink_queue: fix incorrect initialization of copy range field 2^16 = 0xffff, not 0xfffff (note the extra 'f'). Not dangerous since you adjust it to min_t(data_len, skb->len) just after on. Reported-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_queue_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 858fd52c1040..1cb48540f86a 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -112,7 +112,7 @@ instance_create(u_int16_t queue_num, int portid) inst->queue_num = queue_num; inst->peer_portid = portid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; - inst->copy_range = 0xfffff; + inst->copy_range = 0xffff; inst->copy_mode = NFQNL_COPY_NONE; spin_lock_init(&inst->lock); INIT_LIST_HEAD(&inst->queue_list); -- cgit v1.2.3 From a82783c91d5dce680dbd290ebf301a520b0e72a5 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 11 Mar 2013 20:11:01 +0000 Subject: netfilter: ip6t_NPT: restrict to mangle table As the translation is stateless, using it in nat table doesn't work (only initial packet is translated). filter table OUTPUT works but won't re-route the packet after translation. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/ip6t_NPT.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index 83acc1405a18..33608c610276 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c @@ -114,6 +114,7 @@ ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par) static struct xt_target ip6t_npt_target_reg[] __read_mostly = { { .name = "SNPT", + .table = "mangle", .target = ip6t_snpt_tg, .targetsize = sizeof(struct ip6t_npt_tginfo), .checkentry = ip6t_npt_checkentry, @@ -124,6 +125,7 @@ static struct xt_target ip6t_npt_target_reg[] __read_mostly = { }, { .name = "DNPT", + .table = "mangle", .target = ip6t_dnpt_tg, .targetsize = sizeof(struct ip6t_npt_tginfo), .checkentry = ip6t_npt_checkentry, -- cgit v1.2.3 From d66629c1325399cf080ba8b2fb086c10e5439cdd Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 15 Mar 2013 11:00:39 +0800 Subject: Bluetooth: Add support for Dell[QCA 0cf3:0036] Add support for the AR9462 chip T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=0036 Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Cc: Cc: Gustavo Padovan Signed-off-by: Ming Lei Signed-off-by: Gustavo Padovan --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 3095d2e74f24..0a6ef6b694d4 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -73,6 +73,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x03F0, 0x311D) }, /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, @@ -107,6 +108,7 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); static struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e547851870e7..11ac3036bb8a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -131,6 +131,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ + { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, -- cgit v1.2.3 From 7cb035d9e619a8d20f5d3b9791f8cb5160d19e70 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 10 Mar 2013 13:56:08 +0200 Subject: mei: add mei_stop function to stop mei device mei_stop calls mei_reset with disabling the interrupts. It will have the same effect as the open code it replaces in the mei_remove. The reset sequence on remove is required for the Lynx Point LP devices to clean the reset state. mei_stop is called from mei_pci_suspend and mei_remove functions Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/init.c | 18 ++++++++++++++++ drivers/misc/mei/mei_dev.h | 1 + drivers/misc/mei/pci-me.c | 52 +++++++--------------------------------------- 3 files changed, 26 insertions(+), 45 deletions(-) diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 6ec530168afb..356179991a2e 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -183,6 +183,24 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) mei_cl_all_write_clear(dev); } +void mei_stop(struct mei_device *dev) +{ + dev_dbg(&dev->pdev->dev, "stopping the device.\n"); + + mutex_lock(&dev->device_lock); + + cancel_delayed_work(&dev->timer_work); + + mei_wd_stop(dev); + + dev->dev_state = MEI_DEV_POWER_DOWN; + mei_reset(dev, 0); + + mutex_unlock(&dev->device_lock); + + flush_scheduled_work(); +} + diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index cb80166161f0..97873812e33b 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -381,6 +381,7 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec) void mei_device_init(struct mei_device *dev); void mei_reset(struct mei_device *dev, int interrupts); int mei_hw_init(struct mei_device *dev); +void mei_stop(struct mei_device *dev); /* * MEI interrupt functions prototype diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index b40ec0601ab0..b8b5c9c3ad03 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -247,44 +247,14 @@ static void mei_remove(struct pci_dev *pdev) hw = to_me_hw(dev); - mutex_lock(&dev->device_lock); - - cancel_delayed_work(&dev->timer_work); - mei_wd_stop(dev); + dev_err(&pdev->dev, "stop\n"); + mei_stop(dev); mei_pdev = NULL; - if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { - dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; - mei_cl_disconnect(&dev->iamthif_cl); - } - if (dev->wd_cl.state == MEI_FILE_CONNECTED) { - dev->wd_cl.state = MEI_FILE_DISCONNECTING; - mei_cl_disconnect(&dev->wd_cl); - } - - /* Unregistering watchdog device */ mei_watchdog_unregister(dev); - /* remove entry if already in list */ - dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - - if (dev->open_handle_count > 0) - dev->open_handle_count--; - mei_cl_unlink(&dev->wd_cl); - - if (dev->open_handle_count > 0) - dev->open_handle_count--; - mei_cl_unlink(&dev->iamthif_cl); - - dev->iamthif_current_cb = NULL; - dev->me_clients_num = 0; - - mutex_unlock(&dev->device_lock); - - flush_scheduled_work(); - /* disable interrupts */ mei_disable_interrupts(dev); @@ -308,28 +278,20 @@ static int mei_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mei_device *dev = pci_get_drvdata(pdev); - int err; if (!dev) return -ENODEV; - mutex_lock(&dev->device_lock); - cancel_delayed_work(&dev->timer_work); + dev_err(&pdev->dev, "suspend\n"); - /* Stop watchdog if exists */ - err = mei_wd_stop(dev); - /* Set new mei state */ - if (dev->dev_state == MEI_DEV_ENABLED || - dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { - dev->dev_state = MEI_DEV_POWER_DOWN; - mei_reset(dev, 0); - } - mutex_unlock(&dev->device_lock); + mei_stop(dev); + + mei_disable_interrupts(dev); free_irq(pdev->irq, dev); pci_disable_msi(pdev); - return err; + return 0; } static int mei_pci_resume(struct device *device) -- cgit v1.2.3 From 68f8ea184bf7a552b59a38c4b0c7dc243822d2d5 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 10 Mar 2013 13:56:07 +0200 Subject: mei: ME hardware reset needs to be synchronized This fixes failure during initialization on Lynx Point LP devices. ME driver needs to release the device from the reset only after the FW has completed its flow and indicated it by delivering an interrupt to the host. This is the correct behavior for all the ME devices yet the the previous versions are less susceptive to the implementation that ignored FW reset completion indication. We add mei_me_hw_reset_release function which is called after reset from the interrupt thread or directly from mei_reset during power down. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 45ea7185c003..642c6223fa6c 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -151,6 +151,20 @@ static void mei_me_intr_disable(struct mei_device *dev) mei_hcsr_set(hw, hcsr); } +/** + * mei_me_hw_reset_release - release device from the reset + * + * @dev: the device structure + */ +static void mei_me_hw_reset_release(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 hcsr = mei_hcsr_read(hw); + + hcsr |= H_IG; + hcsr &= ~H_RST; + mei_hcsr_set(hw, hcsr); +} /** * mei_me_hw_reset - resets fw via mei csr register. * @@ -169,18 +183,14 @@ static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable) if (intr_enable) hcsr |= H_IE; else - hcsr &= ~H_IE; - - mei_hcsr_set(hw, hcsr); - - hcsr = mei_hcsr_read(hw) | H_IG; - hcsr &= ~H_RST; + hcsr |= ~H_IE; mei_hcsr_set(hw, hcsr); - hcsr = mei_hcsr_read(hw); + if (dev->dev_state == MEI_DEV_POWER_DOWN) + mei_me_hw_reset_release(dev); - dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr); + dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw)); } /** @@ -466,7 +476,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } else { - dev_dbg(&dev->pdev->dev, "FW not ready.\n"); + dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); + mei_me_hw_reset_release(dev); mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } -- cgit v1.2.3 From 347e0899b1c75d907f01ac883ca38d37fe9bfa42 Mon Sep 17 00:00:00 2001 From: Andy King Date: Thu, 7 Mar 2013 07:29:08 -0800 Subject: VMCI: Fix process-to-process DRGAMs. When sending between processes, we always schedule a work item. Our work info struct has the message embedded in the middle, which means that we end up overwriting subsequent fields when we copy the (variable-length) message into it. Move it to the end of the struct. Acked-by: Dmitry Torokhov Signed-off-by: Andy King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_datagram.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_datagram.c b/drivers/misc/vmw_vmci/vmci_datagram.c index ed5c433cd493..f3cdd904fe4d 100644 --- a/drivers/misc/vmw_vmci/vmci_datagram.c +++ b/drivers/misc/vmw_vmci/vmci_datagram.c @@ -42,9 +42,11 @@ struct datagram_entry { struct delayed_datagram_info { struct datagram_entry *entry; - struct vmci_datagram msg; struct work_struct work; bool in_dg_host_queue; + /* msg and msg_payload must be together. */ + struct vmci_datagram msg; + u8 msg_payload[]; }; /* Number of in-flight host->host datagrams */ -- cgit v1.2.3 From 503bded92da283b2f31d87e054c4c6d30c3c2340 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Wed, 20 Feb 2013 17:26:20 +0100 Subject: tty: atmel_serial_probe(): index of atmel_ports[] fix Index of atmel_ports[ATMEL_MAX_UART] should be smaller than ATMEL_MAX_UART. Signed-off-by: Pawel Wieczorkiewicz Acked-by: Nicolas Ferre Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d4a7c241b751..3467462869ce 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -158,7 +158,7 @@ struct atmel_uart_port { }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; -static unsigned long atmel_ports_in_use; +static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART); #ifdef SUPPORT_SYSRQ static struct console atmel_console; @@ -1769,15 +1769,14 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret < 0) /* port id not found in platform data nor device-tree aliases: * auto-enumerate it */ - ret = find_first_zero_bit(&atmel_ports_in_use, - sizeof(atmel_ports_in_use)); + ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART); - if (ret > ATMEL_MAX_UART) { + if (ret >= ATMEL_MAX_UART) { ret = -ENODEV; goto err; } - if (test_and_set_bit(ret, &atmel_ports_in_use)) { + if (test_and_set_bit(ret, atmel_ports_in_use)) { /* port already in use */ ret = -EBUSY; goto err; @@ -1857,7 +1856,7 @@ static int atmel_serial_remove(struct platform_device *pdev) /* "port" is allocated statically, so we shouldn't free it */ - clear_bit(port->line, &atmel_ports_in_use); + clear_bit(port->line, atmel_ports_in_use); clk_put(atmel_port->clk); -- cgit v1.2.3 From 8b5c913f7ee6464849570bacb6bcd9ef0eaf7dce Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Tue, 5 Mar 2013 23:16:48 +0800 Subject: serial: 8250_pci: Add WCH CH352 quirk to avoid Xscale detection The code in 8250.c for detecting ARM/XScale UARTs says: * Try writing and reading the UART_IER_UUE bit (b6). * If it works, this is probably one of the Xscale platform's * internal UARTs. If the above passes, it then goes on to: * It's an Xscale. * We'll leave the UART_IER_UUE bit set to 1 (enabled). However, the CH352 uses the UART_IER_UUE as the LOWPOWER function, so it is readable and writable. According to the datasheet: "LOWPOWER:When the bit is 1, close the internal benchmark clock of serial port to set into low-power status. So it essentially gets mis-detected as Xscale, and gets powered down in the process. The device in question where this was seen is listed by lspci as: Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550]) Re-using the 353 quirk which just sets flags to fixed and type to 16550 is suitable for fixing the 352 as well. Signed-off-by: Wang YanQing Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index aa76825229dc..26e3a97ab157 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1554,6 +1554,7 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d #define PCI_VENDOR_ID_WCH 0x4348 +#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253 #define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 @@ -2172,6 +2173,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH352 2S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH352_2S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, /* * ASIX devices with FIFO bug */ @@ -4870,6 +4879,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + /* * Commtech, Inc. Fastcom adapters */ -- cgit v1.2.3 From c95246c3a2ac796cfa43e76200ede59cb4a1644f Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Sat, 16 Mar 2013 08:22:25 +0100 Subject: Adding in EEH support to the IBM FlashSystem 70/80 device driver Changes in v2 include: o Fixed spelling of guarantee. o Fixed potential memory leak if slot reset fails out. o Changed list_for_each_entry_safe with list_for_each_entry. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/core.c | 203 +++++++++++++++++++++++++++++++++++++- drivers/block/rsxx/cregs.c | 59 +++++++++-- drivers/block/rsxx/dma.c | 216 ++++++++++++++++++++++++++++++----------- drivers/block/rsxx/rsxx_priv.h | 25 ++++- 4 files changed, 436 insertions(+), 67 deletions(-) diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index cbbdff113f46..93f28191a0ff 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,13 @@ static DEFINE_IDA(rsxx_disk_ida); static DEFINE_SPINLOCK(rsxx_ida_lock); /*----------------- Interrupt Control & Handling -------------------*/ + +static void rsxx_mask_interrupts(struct rsxx_cardinfo *card) +{ + card->isr_mask = 0; + card->ier_mask = 0; +} + static void __enable_intr(unsigned int *mask, unsigned int intr) { *mask |= intr; @@ -71,7 +79,8 @@ static void __disable_intr(unsigned int *mask, unsigned int intr) */ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr) { - if (unlikely(card->halt)) + if (unlikely(card->halt) || + unlikely(card->eeh_state)) return; __enable_intr(&card->ier_mask, intr); @@ -80,6 +89,9 @@ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr) void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr) { + if (unlikely(card->eeh_state)) + return; + __disable_intr(&card->ier_mask, intr); iowrite32(card->ier_mask, card->regmap + IER); } @@ -87,7 +99,8 @@ void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr) void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card, unsigned int intr) { - if (unlikely(card->halt)) + if (unlikely(card->halt) || + unlikely(card->eeh_state)) return; __enable_intr(&card->isr_mask, intr); @@ -97,6 +110,9 @@ void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card, void rsxx_disable_ier_and_isr(struct rsxx_cardinfo *card, unsigned int intr) { + if (unlikely(card->eeh_state)) + return; + __disable_intr(&card->isr_mask, intr); __disable_intr(&card->ier_mask, intr); iowrite32(card->ier_mask, card->regmap + IER); @@ -115,6 +131,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata) do { reread_isr = 0; + if (unlikely(card->eeh_state)) + break; + isr = ioread32(card->regmap + ISR); if (isr == 0xffffffff) { /* @@ -304,6 +323,179 @@ static int card_shutdown(struct rsxx_cardinfo *card) return 0; } +static void rsxx_eeh_frozen(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + int i; + + dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n"); + + card->eeh_state = 1; + rsxx_mask_interrupts(card); + + /* + * We need to guarantee that the write for eeh_state and masking + * interrupts does not become reordered. This will prevent a possible + * race condition with the EEH code. + */ + wmb(); + + pci_disable_device(dev); + + rsxx_eeh_save_issued_dmas(card); + + rsxx_eeh_save_issued_creg(card); + + for (i = 0; i < card->n_targets; i++) { + if (card->ctrl[i].status.buf) + pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8, + card->ctrl[i].status.buf, + card->ctrl[i].status.dma_addr); + if (card->ctrl[i].cmd.buf) + pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8, + card->ctrl[i].cmd.buf, + card->ctrl[i].cmd.dma_addr); + } +} + +static void rsxx_eeh_failure(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + int i; + + dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n"); + + card->eeh_state = 1; + + for (i = 0; i < card->n_targets; i++) + del_timer_sync(&card->ctrl[i].activity_timer); + + rsxx_eeh_cancel_dmas(card); +} + +static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card) +{ + unsigned int status; + int iter = 0; + + /* We need to wait for the hardware to reset */ + while (iter++ < 10) { + status = ioread32(card->regmap + PCI_RECONFIG); + + if (status & RSXX_FLUSH_BUSY) { + ssleep(1); + continue; + } + + if (status & RSXX_FLUSH_TIMEOUT) + dev_warn(CARD_TO_DEV(card), "HW: flash controller timeout\n"); + return 0; + } + + /* Hardware failed resetting itself. */ + return -1; +} + +static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev, + enum pci_channel_state error) +{ + if (dev->revision < RSXX_EEH_SUPPORT) + return PCI_ERS_RESULT_NONE; + + if (error == pci_channel_io_perm_failure) { + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + + rsxx_eeh_frozen(dev); + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + unsigned long flags; + int i; + int st; + + dev_warn(&dev->dev, + "IBM FlashSystem PCI: recovering from slot reset.\n"); + + st = pci_enable_device(dev); + if (st) + goto failed_hw_setup; + + pci_set_master(dev); + + st = rsxx_eeh_fifo_flush_poll(card); + if (st) + goto failed_hw_setup; + + rsxx_dma_queue_reset(card); + + for (i = 0; i < card->n_targets; i++) { + st = rsxx_hw_buffers_init(dev, &card->ctrl[i]); + if (st) + goto failed_hw_buffers_init; + } + + if (card->config_valid) + rsxx_dma_configure(card); + + /* Clears the ISR register from spurious interrupts */ + st = ioread32(card->regmap + ISR); + + card->eeh_state = 0; + + st = rsxx_eeh_remap_dmas(card); + if (st) + goto failed_remap_dmas; + + spin_lock_irqsave(&card->irq_lock, flags); + if (card->n_targets & RSXX_MAX_TARGETS) + rsxx_enable_ier_and_isr(card, CR_INTR_ALL_G); + else + rsxx_enable_ier_and_isr(card, CR_INTR_ALL_C); + spin_unlock_irqrestore(&card->irq_lock, flags); + + rsxx_kick_creg_queue(card); + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + if (list_empty(&card->ctrl[i].queue)) { + spin_unlock(&card->ctrl[i].queue_lock); + continue; + } + spin_unlock(&card->ctrl[i].queue_lock); + + queue_work(card->ctrl[i].issue_wq, + &card->ctrl[i].issue_dma_work); + } + + dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n"); + + return PCI_ERS_RESULT_RECOVERED; + +failed_hw_buffers_init: +failed_remap_dmas: + for (i = 0; i < card->n_targets; i++) { + if (card->ctrl[i].status.buf) + pci_free_consistent(card->dev, + STATUS_BUFFER_SIZE8, + card->ctrl[i].status.buf, + card->ctrl[i].status.dma_addr); + if (card->ctrl[i].cmd.buf) + pci_free_consistent(card->dev, + COMMAND_BUFFER_SIZE8, + card->ctrl[i].cmd.buf, + card->ctrl[i].cmd.dma_addr); + } +failed_hw_setup: + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + +} + /*----------------- Driver Initialization & Setup -------------------*/ /* Returns: 0 if the driver is compatible with the device -1 if the driver is NOT compatible with the device */ @@ -383,6 +575,7 @@ static int rsxx_pci_probe(struct pci_dev *dev, spin_lock_init(&card->irq_lock); card->halt = 0; + card->eeh_state = 0; spin_lock_irq(&card->irq_lock); rsxx_disable_ier_and_isr(card, CR_INTR_ALL); @@ -593,6 +786,11 @@ static void rsxx_pci_shutdown(struct pci_dev *dev) card_shutdown(card); } +static const struct pci_error_handlers rsxx_err_handler = { + .error_detected = rsxx_error_detected, + .slot_reset = rsxx_slot_reset, +}; + static DEFINE_PCI_DEVICE_TABLE(rsxx_pci_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS70_FLASH)}, {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS80_FLASH)}, @@ -608,6 +806,7 @@ static struct pci_driver rsxx_pci_driver = { .remove = rsxx_pci_remove, .suspend = rsxx_pci_suspend, .shutdown = rsxx_pci_shutdown, + .err_handler = &rsxx_err_handler, }; static int __init rsxx_core_init(void) diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index 0539a25877eb..4b5c020a0a65 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -58,7 +58,7 @@ static struct kmem_cache *creg_cmd_pool; #error Unknown endianess!!! Aborting... #endif -static void copy_to_creg_data(struct rsxx_cardinfo *card, +static int copy_to_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) @@ -66,6 +66,9 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card, int i = 0; u32 *data = buf; + if (unlikely(card->eeh_state)) + return -EIO; + for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on @@ -76,10 +79,12 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card, else iowrite32(data[i], card->regmap + CREG_DATA(i)); } + + return 0; } -static void copy_from_creg_data(struct rsxx_cardinfo *card, +static int copy_from_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) @@ -87,6 +92,9 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card, int i = 0; u32 *data = buf; + if (unlikely(card->eeh_state)) + return -EIO; + for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on @@ -97,19 +105,32 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card, else data[i] = ioread32(card->regmap + CREG_DATA(i)); } + + return 0; } static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) { + int st; + + if (unlikely(card->eeh_state)) + return; + iowrite32(cmd->addr, card->regmap + CREG_ADD); iowrite32(cmd->cnt8, card->regmap + CREG_CNT); if (cmd->op == CREG_OP_WRITE) { - if (cmd->buf) - copy_to_creg_data(card, cmd->cnt8, - cmd->buf, cmd->stream); + if (cmd->buf) { + st = copy_to_creg_data(card, cmd->cnt8, + cmd->buf, cmd->stream); + if (st) + return; + } } + if (unlikely(card->eeh_state)) + return; + /* Setting the valid bit will kick off the command. */ iowrite32(cmd->op, card->regmap + CREG_CMD); } @@ -272,7 +293,7 @@ static void creg_cmd_done(struct work_struct *work) goto creg_done; } - copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream); + st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream); } creg_done: @@ -675,6 +696,32 @@ int rsxx_reg_access(struct rsxx_cardinfo *card, return 0; } +void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card) +{ + struct creg_cmd *cmd = NULL; + + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + + if (cmd) { + del_timer_sync(&card->creg_ctrl.cmd_timer); + + spin_lock_bh(&card->creg_ctrl.lock); + list_add(&cmd->list, &card->creg_ctrl.queue); + card->creg_ctrl.q_depth++; + card->creg_ctrl.active = 0; + spin_unlock_bh(&card->creg_ctrl.lock); + } +} + +void rsxx_kick_creg_queue(struct rsxx_cardinfo *card) +{ + spin_lock_bh(&card->creg_ctrl.lock); + if (!list_empty(&card->creg_ctrl.queue)) + creg_kick_queue(card); + spin_unlock_bh(&card->creg_ctrl.lock); +} + /*------------ Initialization & Setup --------------*/ int rsxx_creg_setup(struct rsxx_cardinfo *card) { diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index efd75b55a670..60d344d002ec 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -81,9 +81,6 @@ enum rsxx_hw_status { HW_STATUS_FAULT = 0x08, }; -#define STATUS_BUFFER_SIZE8 4096 -#define COMMAND_BUFFER_SIZE8 4096 - static struct kmem_cache *rsxx_dma_pool; struct dma_tracker { @@ -122,7 +119,7 @@ static unsigned int rsxx_get_dma_tgt(struct rsxx_cardinfo *card, u64 addr8) return tgt; } -static void rsxx_dma_queue_reset(struct rsxx_cardinfo *card) +void rsxx_dma_queue_reset(struct rsxx_cardinfo *card) { /* Reset all DMA Command/Status Queues */ iowrite32(DMA_QUEUE_RESET, card->regmap + RESET); @@ -210,7 +207,8 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) u32 q_depth = 0; u32 intr_coal; - if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE) + if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE || + unlikely(card->eeh_state)) return; for (i = 0; i < card->n_targets; i++) @@ -223,31 +221,26 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) } /*----------------- RSXX DMA Handling -------------------*/ -static void rsxx_complete_dma(struct rsxx_cardinfo *card, +static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma, unsigned int status) { if (status & DMA_SW_ERR) - printk_ratelimited(KERN_ERR - "SW Error in DMA(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_sw_err++; if (status & DMA_HW_FAULT) - printk_ratelimited(KERN_ERR - "HW Fault in DMA(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_hw_fault++; if (status & DMA_CANCELLED) - printk_ratelimited(KERN_ERR - "DMA Cancelled(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_cancelled++; if (dma->dma_addr) - pci_unmap_page(card->dev, dma->dma_addr, get_dma_size(dma), + pci_unmap_page(ctrl->card->dev, dma->dma_addr, + get_dma_size(dma), dma->cmd == HW_CMD_BLK_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (dma->cb) - dma->cb(card, dma->cb_data, status ? 1 : 0); + dma->cb(ctrl->card, dma->cb_data, status ? 1 : 0); kmem_cache_free(rsxx_dma_pool, dma); } @@ -330,14 +323,15 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl, if (requeue_cmd) rsxx_requeue_dma(ctrl, dma); else - rsxx_complete_dma(ctrl->card, dma, status); + rsxx_complete_dma(ctrl, dma, status); } static void dma_engine_stalled(unsigned long data) { struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data; - if (atomic_read(&ctrl->stats.hw_q_depth) == 0) + if (atomic_read(&ctrl->stats.hw_q_depth) == 0 || + unlikely(ctrl->card->eeh_state)) return; if (ctrl->cmd.idx != ioread32(ctrl->regmap + SW_CMD_IDX)) { @@ -369,7 +363,8 @@ static void rsxx_issue_dmas(struct work_struct *work) ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work); hw_cmd_buf = ctrl->cmd.buf; - if (unlikely(ctrl->card->halt)) + if (unlikely(ctrl->card->halt) || + unlikely(ctrl->card->eeh_state)) return; while (1) { @@ -397,7 +392,7 @@ static void rsxx_issue_dmas(struct work_struct *work) */ if (unlikely(ctrl->card->dma_fault)) { push_tracker(ctrl->trackers, tag); - rsxx_complete_dma(ctrl->card, dma, DMA_CANCELLED); + rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); continue; } @@ -435,6 +430,12 @@ static void rsxx_issue_dmas(struct work_struct *work) atomic_add(cmds_pending, &ctrl->stats.hw_q_depth); mod_timer(&ctrl->activity_timer, jiffies + DMA_ACTIVITY_TIMEOUT); + + if (unlikely(ctrl->card->eeh_state)) { + del_timer_sync(&ctrl->activity_timer); + return; + } + iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); } } @@ -453,7 +454,8 @@ static void rsxx_dma_done(struct work_struct *work) hw_st_buf = ctrl->status.buf; if (unlikely(ctrl->card->halt) || - unlikely(ctrl->card->dma_fault)) + unlikely(ctrl->card->dma_fault) || + unlikely(ctrl->card->eeh_state)) return; count = le16_to_cpu(hw_st_buf[ctrl->status.idx].count); @@ -498,7 +500,7 @@ static void rsxx_dma_done(struct work_struct *work) if (status) rsxx_handle_dma_error(ctrl, dma, status); else - rsxx_complete_dma(ctrl->card, dma, 0); + rsxx_complete_dma(ctrl, dma, 0); push_tracker(ctrl->trackers, tag); @@ -717,20 +719,54 @@ bvec_err: /*----------------- DMA Engine Initialization & Setup -------------------*/ +int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl) +{ + ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8, + &ctrl->status.dma_addr); + ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8, + &ctrl->cmd.dma_addr); + if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL) + return -ENOMEM; + + memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8); + iowrite32(lower_32_bits(ctrl->status.dma_addr), + ctrl->regmap + SB_ADD_LO); + iowrite32(upper_32_bits(ctrl->status.dma_addr), + ctrl->regmap + SB_ADD_HI); + + memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8); + iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO); + iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI); + + ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT); + if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) { + dev_crit(&dev->dev, "Failed reading status cnt x%x\n", + ctrl->status.idx); + return -EINVAL; + } + iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT); + iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT); + + ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX); + if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) { + dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n", + ctrl->status.idx); + return -EINVAL; + } + iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX); + iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); + + return 0; +} + static int rsxx_dma_ctrl_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl) { int i; + int st; memset(&ctrl->stats, 0, sizeof(ctrl->stats)); - ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8, - &ctrl->status.dma_addr); - ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8, - &ctrl->cmd.dma_addr); - if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL) - return -ENOMEM; - ctrl->trackers = vmalloc(DMA_TRACKER_LIST_SIZE8); if (!ctrl->trackers) return -ENOMEM; @@ -760,33 +796,9 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev, INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas); INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done); - memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8); - iowrite32(lower_32_bits(ctrl->status.dma_addr), - ctrl->regmap + SB_ADD_LO); - iowrite32(upper_32_bits(ctrl->status.dma_addr), - ctrl->regmap + SB_ADD_HI); - - memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8); - iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO); - iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI); - - ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT); - if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) { - dev_crit(&dev->dev, "Failed reading status cnt x%x\n", - ctrl->status.idx); - return -EINVAL; - } - iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT); - iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT); - - ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX); - if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) { - dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n", - ctrl->status.idx); - return -EINVAL; - } - iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX); - iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); + st = rsxx_hw_buffers_init(dev, ctrl); + if (st) + return st; return 0; } @@ -822,7 +834,7 @@ static int rsxx_dma_stripe_setup(struct rsxx_cardinfo *card, return 0; } -static int rsxx_dma_configure(struct rsxx_cardinfo *card) +int rsxx_dma_configure(struct rsxx_cardinfo *card) { u32 intr_coal; @@ -968,6 +980,94 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card) } } +void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) +{ + int i; + int j; + int cnt; + struct rsxx_dma *dma; + struct list_head issued_dmas[card->n_targets]; + + for (i = 0; i < card->n_targets; i++) { + INIT_LIST_HEAD(&issued_dmas[i]); + cnt = 0; + for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) { + dma = get_tracker_dma(card->ctrl[i].trackers, j); + if (dma == NULL) + continue; + + if (dma->cmd == HW_CMD_BLK_WRITE) + card->ctrl[i].stats.writes_issued--; + else if (dma->cmd == HW_CMD_BLK_DISCARD) + card->ctrl[i].stats.discards_issued--; + else + card->ctrl[i].stats.reads_issued--; + + list_add_tail(&dma->list, &issued_dmas[i]); + push_tracker(card->ctrl[i].trackers, j); + cnt++; + } + + spin_lock(&card->ctrl[i].queue_lock); + list_splice(&issued_dmas[i], &card->ctrl[i].queue); + + atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth); + card->ctrl[i].stats.sw_q_depth += cnt; + card->ctrl[i].e_cnt = 0; + + list_for_each_entry(dma, &card->ctrl[i].queue, list) { + if (dma->dma_addr) + pci_unmap_page(card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + } + spin_unlock(&card->ctrl[i].queue_lock); + } +} + +void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card) +{ + struct rsxx_dma *dma; + struct rsxx_dma *tmp; + int i; + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) { + list_del(&dma->list); + + rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED); + } + spin_unlock(&card->ctrl[i].queue_lock); + } +} + +int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) +{ + struct rsxx_dma *dma; + struct rsxx_dma *tmp; + int i; + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + list_for_each_entry(dma, &card->ctrl[i].queue, list) { + dma->dma_addr = pci_map_page(card->dev, dma->page, + dma->pg_off, get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + if (!dma->dma_addr) { + kmem_cache_free(rsxx_dma_pool, dma); + return -ENOMEM; + } + } + spin_unlock(&card->ctrl[i].queue_lock); + } + + return 0; +} int rsxx_dma_init(void) { diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index f5a95f75bd57..8a7ac87f1dc5 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -64,6 +64,9 @@ struct proc_cmd; #define RSXX_MAX_OUTSTANDING_CMDS 255 #define RSXX_CS_IDX_MASK 0xff +#define STATUS_BUFFER_SIZE8 4096 +#define COMMAND_BUFFER_SIZE8 4096 + #define RSXX_MAX_TARGETS 8 struct dma_tracker_list; @@ -88,6 +91,9 @@ struct rsxx_dma_stats { u32 discards_failed; u32 done_rescheduled; u32 issue_rescheduled; + u32 dma_sw_err; + u32 dma_hw_fault; + u32 dma_cancelled; u32 sw_q_depth; /* Number of DMAs on the SW queue. */ atomic_t hw_q_depth; /* Number of DMAs queued to HW. */ }; @@ -113,6 +119,7 @@ struct rsxx_dma_ctrl { struct rsxx_cardinfo { struct pci_dev *dev; unsigned int halt; + unsigned int eeh_state; void __iomem *regmap; spinlock_t irq_lock; @@ -221,6 +228,7 @@ enum rsxx_pci_regmap { PERF_RD512_HI = 0xac, PERF_WR512_LO = 0xb0, PERF_WR512_HI = 0xb4, + PCI_RECONFIG = 0xb8, }; enum rsxx_intr { @@ -234,6 +242,8 @@ enum rsxx_intr { CR_INTR_DMA5 = 0x00000080, CR_INTR_DMA6 = 0x00000100, CR_INTR_DMA7 = 0x00000200, + CR_INTR_ALL_C = 0x0000003f, + CR_INTR_ALL_G = 0x000003ff, CR_INTR_DMA_ALL = 0x000003f5, CR_INTR_ALL = 0xffffffff, }; @@ -250,8 +260,14 @@ enum rsxx_pci_reset { DMA_QUEUE_RESET = 0x00000001, }; +enum rsxx_hw_fifo_flush { + RSXX_FLUSH_BUSY = 0x00000002, + RSXX_FLUSH_TIMEOUT = 0x00000004, +}; + enum rsxx_pci_revision { RSXX_DISCARD_SUPPORT = 2, + RSXX_EEH_SUPPORT = 3, }; enum rsxx_creg_cmd { @@ -357,11 +373,17 @@ int rsxx_dma_setup(struct rsxx_cardinfo *card); void rsxx_dma_destroy(struct rsxx_cardinfo *card); int rsxx_dma_init(void); void rsxx_dma_cleanup(void); +void rsxx_dma_queue_reset(struct rsxx_cardinfo *card); +int rsxx_dma_configure(struct rsxx_cardinfo *card); int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, struct bio *bio, atomic_t *n_dmas, rsxx_dma_cb cb, void *cb_data); +int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl); +void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card); +void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card); +int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card); /***** cregs.c *****/ int rsxx_creg_write(struct rsxx_cardinfo *card, u32 addr, @@ -386,10 +408,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card); void rsxx_creg_destroy(struct rsxx_cardinfo *card); int rsxx_creg_init(void); void rsxx_creg_cleanup(void); - int rsxx_reg_access(struct rsxx_cardinfo *card, struct rsxx_reg_access __user *ucmd, int read); +void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card); +void rsxx_kick_creg_queue(struct rsxx_cardinfo *card); -- cgit v1.2.3 From 351a2c6e7d265f97799ec7f6b1dde7fc7cb4b92d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 16 Mar 2013 10:10:48 +0100 Subject: rsxx: fix missing unlock on error return in rsxx_eeh_remap_dmas() Spotted by Fenguan Wu's super build robot. Signed-off-by: Jens Axboe --- drivers/block/rsxx/dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 60d344d002ec..d523e9c56578 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -1059,6 +1059,7 @@ int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (!dma->dma_addr) { + spin_unlock(&card->ctrl[i].queue_lock); kmem_cache_free(rsxx_dma_pool, dma); return -ENOMEM; } -- cgit v1.2.3 From 605c357bb40ce412c086f3a928d07c1d4349b95b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 15 Mar 2013 19:16:52 -0500 Subject: ARM: ep93xx: Fix wait for UART FIFO to be empty Commit 210dce5f "ARM: ep93xx: properly wait for UART FIFO to be empty" Removed the timeout loop while waiting for the uart transmit fifo to empty. Some bootloaders leave the uart in a state where there might be bytes in the uart that are not transmitted when execution is handed over to the kernel. This results in a deadlocked system while waiting for the fifo to empty. Add back the timeout wait to prevent the deadlock. Increase the wait time to hopefully prevent the decompressor corruption that lead to commit 210dce5f. This corruption was probably due to a slow uart baudrate. The 10* increase in the wait time should be enough for all cases. Signed-off-by: H Hartley Sweeten Acked-by: Florian Fainelli Signed-off-by: Ryan Mallon --- arch/arm/mach-ep93xx/include/mach/uncompress.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h index d2afb4dd82ab..b5cc77d2380b 100644 --- a/arch/arm/mach-ep93xx/include/mach/uncompress.h +++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h @@ -47,9 +47,13 @@ static void __raw_writel(unsigned int value, unsigned int ptr) static inline void putc(int c) { - /* Transmit fifo not full? */ - while (__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF) - ; + int i; + + for (i = 0; i < 10000; i++) { + /* Transmit fifo not full? */ + if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)) + break; + } __raw_writeb(c, PHYS_UART_DATA); } -- cgit v1.2.3 From 92f28d973cce45ef5823209aab3138eb45d8b349 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 15 Mar 2013 01:03:33 -0700 Subject: scm: Require CAP_SYS_ADMIN over the current pidns to spoof pids. Don't allow spoofing pids over unix domain sockets in the corner cases where a user has created a user namespace but has not yet created a pid namespace. Cc: stable@vger.kernel.org Reported-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" --- net/core/scm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/scm.c b/net/core/scm.c index 905dcc6ad1e3..2dc6cdaaae8a 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,8 @@ static __inline__ int scm_check_creds(struct ucred *creds) if (!uid_valid(uid) || !gid_valid(gid)) return -EINVAL; - if ((creds->pid == task_tgid_vnr(current) || nsown_capable(CAP_SYS_ADMIN)) && + if ((creds->pid == task_tgid_vnr(current) || + ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) && ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) && ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || -- cgit v1.2.3 From aabd6a8fa5a933bdf968cd86e34122745c1960e8 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Mon, 18 Mar 2013 19:19:14 +1030 Subject: Revert "virtio_console: Initialize guest_connected=true for rproc_serial" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8078db789a92b10ff6e2d713231b5367e014c53b, and adds a lengthy comment explaining the problem area. The reverted patch caused opening of ports to fail for rproc_serial. In probe guest_connected was set to true, but port_fops_open() fails with -EMFILE if guest_connected already is true. Signed-off-by: Sjur Brændeland Acked-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e905d5f53051..e6ba6b7887e9 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1436,7 +1436,7 @@ static int add_port(struct ports_device *portdev, u32 id) * rproc_serial does not want the console port, only * the generic port implementation. */ - port->host_connected = port->guest_connected = true; + port->host_connected = true; else if (!use_multiport(port->portdev)) { /* * If we're not using multiport support, @@ -1752,13 +1752,23 @@ static void in_intr(struct virtqueue *vq) port->inbuf = get_inbuf(port); /* - * Don't queue up data when port is closed. This condition + * Normally the port should not accept data when the port is + * closed. For generic serial ports, the host won't (shouldn't) + * send data till the guest is connected. But this condition * can be reached when a console port is not yet connected (no - * tty is spawned) and the host sends out data to console - * ports. For generic serial ports, the host won't - * (shouldn't) send data till the guest is connected. + * tty is spawned) and the other side sends out data over the + * vring, or when a remote devices start sending data before + * the ports are opened. + * + * A generic serial port will discard data if not connected, + * while console ports and rproc-serial ports accepts data at + * any time. rproc-serial is initiated with guest_connected to + * false because port_fops_open expects this. Console ports are + * hooked up with an HVC console and is initialized with + * guest_connected to true. */ - if (!port->guest_connected) + + if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) discard_port_data(port); spin_unlock_irqrestore(&port->inbuf_lock, flags); -- cgit v1.2.3 From a37b2dc52b88ccd926099d852eae1bb324bc92eb Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Sat, 2 Mar 2013 12:31:39 +0530 Subject: ARC: Remove SET_PERSONALITY (tracks cross-arch change) Tracks commit e72837e3e7b "default SET_PERSONALITY() in linux/elf.h" Signed-off-by: Vineet Gupta --- arch/arc/include/asm/elf.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arc/include/asm/elf.h b/arch/arc/include/asm/elf.h index f4c8d36ebecb..a26282857683 100644 --- a/arch/arc/include/asm/elf.h +++ b/arch/arc/include/asm/elf.h @@ -72,7 +72,4 @@ extern int elf_check_arch(const struct elf32_hdr *); */ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) \ - set_personality(PER_LINUX | (current->personality & (~PER_MASK))) - #endif -- cgit v1.2.3 From 3d464d9b71ef2f2b40a4bc9dcf06794fd1be9d12 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 18 Mar 2013 09:45:42 -0400 Subject: HID: usbhid: quirk for Realtek Multi-card reader This device needs to be added to the quirks list with HID_QUIRK_NO_INIT_REPORTS, otherwise it causes 10 seconds timeout during report initialization. This fixes Red Hat bugzilla https://bugzilla.redhat.com/show_bug.cgi?id=806587 Cc: stable@vger.kernel.org Signed-off-by: Josh Boyer Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6e5c2ffa8d96..3fc5c33561d5 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -681,6 +681,9 @@ #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 +#define USB_VENDOR_ID_REALTEK 0x0bda +#define USB_DEVICE_ID_REALTEK_READER 0x0152 + #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 #define USB_DEVICE_ID_ROCCAT_ISKU 0x319c diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index e0e6abf1cd3b..e991d81602b6 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -80,6 +80,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, -- cgit v1.2.3 From 620ae90ed8ca8b6e40cb9e10279b4f5ef9f0ab81 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 18 Mar 2013 09:47:02 -0400 Subject: HID: usbhid: quirk for MSI GX680R led panel This keyboard backlight device causes a 10 second delay to boot. Add it to the quirk list with HID_QUIRK_NO_INIT_REPORTS. This fixes Red Hat bugzilla https://bugzilla.redhat.com/show_bug.cgi?id=907221 Cc: stable@vger.kernel.org Signed-off-by: Josh Boyer Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3fc5c33561d5..49b88a0608fb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -587,6 +587,9 @@ #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 +#define USB_VENDOR_ID_MSI 0x1770 +#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 + #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index e991d81602b6..476c984dbdf3 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,6 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDIR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v1.2.3 From 570637dc8eeb2faba06228d497ff40bb019bcc93 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 18 Mar 2013 15:50:10 +0100 Subject: HID: usbhid: fix build problem Fix build problem caused by typo introduced by 620ae90ed8 ("HID: usbhid: quirk for MSI GX680R led panel"). Reported-by: fengguang.wu@intel.com Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 476c984dbdf3..19b8360f2330 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDIR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v1.2.3 From ebaf5795ef57a70a042ea259448a465024e2821d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 18 Mar 2013 23:45:11 +0800 Subject: Bluetooth: Add support for Dell[QCA 0cf3:817a] Add support for the AR9462 chip T: Bus=03 Lev=01 Prnt=01 Port=08 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=817a Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Cc: Cc: Gustavo Padovan Signed-off-by: Ming Lei Signed-off-by: Gustavo Padovan --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 0a6ef6b694d4..8af01c177ce5 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -77,6 +77,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, + { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, { USB_DEVICE(0x04CA, 0x3005) }, @@ -112,6 +113,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 11ac3036bb8a..2cc5f774a29c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -135,6 +135,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, -- cgit v1.2.3 From 66db3feb486c01349f767b98ebb10b0c3d2d021b Mon Sep 17 00:00:00 2001 From: CQ Tang Date: Mon, 18 Mar 2013 11:02:21 -0400 Subject: x86-64: Fix the failure case in copy_user_handle_tail() The increment of "to" in copy_user_handle_tail() will have incremented before a failure has been noted. This causes us to skip a byte in the failure case. Only do the increment when assured there is no failure. Signed-off-by: CQ Tang Link: http://lkml.kernel.org/r/20130318150221.8439.993.stgit@phlsvslse11.ph.intel.com Signed-off-by: Mike Marciniszyn Signed-off-by: H. Peter Anvin Cc: --- arch/x86/lib/usercopy_64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 05928aae911e..906fea315791 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -74,10 +74,10 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest) char c; unsigned zero_len; - for (; len; --len) { + for (; len; --len, to++) { if (__get_user_nocheck(c, from++, sizeof(char))) break; - if (__put_user_nocheck(c, to++, sizeof(char))) + if (__put_user_nocheck(c, to, sizeof(char))) break; } -- cgit v1.2.3 From a517b608fa3d9b65930ef53ffe4a2f9800e10f7d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 18 Mar 2013 10:49:07 -0400 Subject: nfsd: only unhash DRC entries that are in the hashtable It's not safe to call hlist_del() on a newly initialized hlist_node. That leads to a NULL pointer dereference. Only do that if the entry is hashed. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfscache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 62c1ee128aeb..18509bd6f587 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -102,7 +102,8 @@ nfsd_reply_cache_free_locked(struct svc_cacherep *rp) { if (rp->c_type == RC_REPLBUFF) kfree(rp->c_replvec.iov_base); - hlist_del(&rp->c_hash); + if (!hlist_unhashed(&rp->c_hash)) + hlist_del(&rp->c_hash); list_del(&rp->c_lru); --num_drc_entries; kmem_cache_free(drc_slab, rp); -- cgit v1.2.3 From 7f42ace3118afedbd1848a349d01a11d9ca13d41 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 14 Mar 2013 12:48:40 +0100 Subject: iwl3945: fix length of dma buffers commit bdb084b22d8aee66c87af5e9c36bd6cf7f3bccfd Author: Stanislaw Gruszka Date: Wed Feb 13 15:49:08 2013 +0100 iwlegacy: more checks for dma mapping errors broke il3945_tx_skb() dma buffer length settings, what results on firmware errors like showed below and make 3945 device non usable. iwl3945 0000:02:00.0: Microcode SW error detected. Restarting 0x82000008. iwl3945 0000:02:00.0: Loaded firmware version: 15.32.2.9 iwl3945 0000:02:00.0: Start IWL Error Log Dump: iwl3945 0000:02:00.0: Status: 0x000202E4, count: 1 iwl3945 0000:02:00.0: Desc Time asrtPC blink2 ilink1 nmiPC Line iwl3945 0000:02:00.0: SYSASSERT (0x5) 0000208934 0x008B6 0x0035E 0x00320 0x00000 267 iwl3945 0000:02:00.0: Error Reply type 0x00000001 cmd Reported-by: Zdenek Kabelac Reported-by: Krzysztof Kolasa Reported-by: Pedro Francisco Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945-mac.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 3630a41df50d..c353b5f19c8c 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il, dma_addr_t txcmd_phys; int txq_id = skb_get_queue_mapping(skb); u16 len, idx, hdr_len; + u16 firstlen, secondlen; u8 id; u8 unicast; u8 sta_id; @@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il, len = sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) + hdr_len; - len = (len + 3) & ~3; + firstlen = (len + 3) & ~3; /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); + pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, + PCI_DMA_TODEVICE); if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { + secondlen = skb->len - hdr_len; + if (secondlen > 0) { phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, len, + pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, PCI_DMA_TODEVICE); if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) goto drop_unlock; @@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il, /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ - il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); + il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, len); - if (len) - il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, - U32_PAD(len)); + dma_unmap_len_set(out_meta, len, firstlen); + if (secondlen > 0) + il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0, + U32_PAD(secondlen)); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; -- cgit v1.2.3 From 74632d11a133b5baf6b9d622dd19d2f944d93d94 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Mar 2013 14:53:31 +0100 Subject: ath9k_hw: revert chainmask to user configuration after calibration The commit 'ath9k_hw: fix calibration issues on chainmask that don't include chain 0' changed the hardware chainmask to the chip chainmask for the duration of the calibration, but the revert to user configuration in the reset path runs too early. That causes some issues with limiting the number of antennas (including spurious failure in hardware-generated packets). Fix this by reverting the chainmask after the essential parts of the calibration that need the workaround, and before NF calibration is run. Signed-off-by: Felix Fietkau Reported-by: Wojciech Dubowik Tested-by: Wojciech Dubowik Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4cc13940c895..f76c3ca07a45 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; + /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); if (rtt) { @@ -1150,6 +1151,9 @@ skip_tx_iqcal: ar9003_hw_rtt_disable(ah); } + /* Revert chainmask to runtime parameters */ + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; -- cgit v1.2.3 From 01d4ab96d2e7fceaad204e5a8710ce34e229b8c5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Mar 2013 16:18:44 +0100 Subject: ath9k: limit tx path hang check to normal data queues The beacon and multicast-buffer queues are managed by the beacon tasklet, and the generic tx path hang check does not help in any way here. Running it on those queues anyway can introduce some race conditions leading to unnecessary chip resets. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/link.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index ade3afb21f91..39c84ecf6a42 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work) int i; bool needreset = false; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->tx.txq[i]; - ath_txq_lock(sc, txq); - if (txq->axq_depth) { - if (txq->axq_tx_inprogress) { - needreset = true; - ath_txq_unlock(sc, txq); - break; - } else { - txq->axq_tx_inprogress = true; - } + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; + + ath_txq_lock(sc, txq); + if (txq->axq_depth) { + if (txq->axq_tx_inprogress) { + needreset = true; + ath_txq_unlock(sc, txq); + break; + } else { + txq->axq_tx_inprogress = true; } - ath_txq_unlock_complete(sc, txq); } + ath_txq_unlock_complete(sc, txq); + } if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, -- cgit v1.2.3 From 00d7ea11ff0783e24fe70778f3141270b561aaa1 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 15 Mar 2013 18:47:05 -0700 Subject: mwifiex: fix race when queuing commands Running the following script repeatedly on XO-4 with SD8787 produces command timeout and system lockup. insmod mwifiex_sdio.ko sleep 1 ifconfig eth0 up iwlist eth0 scan & sleep 0.5 rmmod mwifiex_sdio mwifiex_send_cmd_async() is called for sync as well as async commands. (mwifiex_send_cmd_sync() internally calls it for sync command.) "adapter->cmd_queued" gets filled inside mwifiex_send_cmd_async() routine for both types of commands. But it is used only for sync commands in mwifiex_wait_queue_complete(). This could lead to a race when two threads try to queue a sync command with another sync/async command simultaneously. Get rid of global variable and pass command node as a parameter to mwifiex_wait_queue_complete() to fix the problem. Cc: # 3.8 Reported-by: Daniel Drake Tested-by: Daniel Drake Tested-by: Marco Cesarano Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 5 ++--- drivers/net/wireless/mwifiex/main.h | 4 ++-- drivers/net/wireless/mwifiex/scan.c | 8 ++++---- drivers/net/wireless/mwifiex/sta_ioctl.c | 10 ++-------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 20a6c5555873..2ffabddbcfca 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -484,8 +484,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, data_buf); - if (!ret) - ret = mwifiex_wait_queue_complete(adapter); return ret; } @@ -588,9 +586,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, if (cmd_no == HostCmd_CMD_802_11_SCAN) { mwifiex_queue_scan_cmd(priv, cmd_node); } else { - adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); queue_work(adapter->workqueue, &adapter->main_work); + if (cmd_node->wait_q_enabled) + ret = mwifiex_wait_queue_complete(adapter, cmd_node); } return ret; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 553adfb0aa81..7035ade9af74 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -723,7 +723,6 @@ struct mwifiex_adapter { u16 cmd_wait_q_required; struct mwifiex_wait_queue cmd_wait_q; u8 scan_wait_q_woken; - struct cmd_ctrl_node *cmd_queued; spinlock_t queue_lock; /* lock for tx queues */ struct completion fw_load; u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; @@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, struct mwifiex_multicast_list *mcast_list); int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, struct net_device *dev); -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_queued); int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct cfg80211_ssid *req_ssid); int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a97..d215b4d3c51b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,13 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); queue_work(adapter->workqueue, &adapter->main_work); + + /* Perform internal scan synchronously */ + if (!priv->scan_request) + mwifiex_wait_queue_complete(adapter, cmd_node); } else { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1946,9 +1949,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv, /* Normal scan */ ret = mwifiex_scan_networks(priv, NULL); - if (!ret) - ret = mwifiex_wait_queue_complete(priv->adapter); - up(&priv->async_sem); return ret; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 9f33c92c90f5..13100f8de3db 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, * This function waits on a cmd wait queue. It also cancels the pending * request after waking up, in case of errors. */ -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_queued) { int status; - struct cmd_ctrl_node *cmd_queued; - - if (!adapter->cmd_queued) - return 0; - - cmd_queued = adapter->cmd_queued; - adapter->cmd_queued = NULL; dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); -- cgit v1.2.3 From a3e240cacc93a06bff3313e28938e980d01a2160 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 15 Mar 2013 18:47:06 -0700 Subject: mwifiex: skip pending commands after function shutdown During rmmod mwifiex_sdio processing FUNC_SHUTDOWN command is sent to firmware. Firmware expcets only FUNC_INIT once WLAN function is shut down. Any command pending in the command queue should be ignored and freed. Cc: # 3.8 Tested-by: Daniel Drake Tested-by: Marco Cesarano Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 2ffabddbcfca..b5c8b962ce12 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, return -1; } + cmd_code = le16_to_cpu(host_cmd->command); + cmd_size = le16_to_cpu(host_cmd->size); + + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && + cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && + cmd_code != HostCmd_CMD_FUNC_INIT) { + dev_err(adapter->dev, + "DNLD_CMD: FW in reset state, ignore cmd %#x\n", + cmd_code); + mwifiex_complete_cmd(adapter, cmd_node); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + /* Set command sequence number */ adapter->seq_num++; host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO @@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, adapter->curr_cmd = cmd_node; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - cmd_code = le16_to_cpu(host_cmd->command); - cmd_size = le16_to_cpu(host_cmd->size); - /* Adjust skb length */ if (cmd_node->cmd_skb->len > cmd_size) /* -- cgit v1.2.3 From 084c7189acb3f969c855536166042e27f5dd703f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 15 Mar 2013 18:47:07 -0700 Subject: mwifiex: cancel cmd timer and free curr_cmd in shutdown process curr_cmd points to the command that is in processing or waiting for its command response from firmware. If the function shutdown happens to occur at this time we should cancel the cmd timer and put the command back to free queue. Cc: # 3.8 Tested-by: Marco Cesarano Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e38aa9b3663d..0ff4c37ab42a 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) return ret; } + /* cancel current command */ + if (adapter->curr_cmd) { + dev_warn(adapter->dev, "curr_cmd is still in processing\n"); + del_timer(&adapter->cmd_timer); + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; + } + /* shut down mwifiex */ dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); -- cgit v1.2.3 From 36ef0b473fbf43d5db23eea4616cc1d18cec245f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sun, 17 Mar 2013 11:54:04 +0200 Subject: rtlwifi: usb: add missing freeing of skbuff Signed-off-by: Jussi Kivilinna Acked-by: Larry Finger Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 156b52732f3d..5847d6d0881e 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(!_urb)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't allocate urb. Drop skb!\n"); + kfree_skb(skb); return; } _rtl_submit_tx_urb(hw, _urb); -- cgit v1.2.3 From 0e5e098ac22dae38f957e951b70d3cf73beff0f7 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 11 Mar 2013 09:39:55 +0000 Subject: xen-blkback: fix dispatch_rw_block_io() error path Commit 7708992 ("xen/blkback: Seperate the bio allocation and the bio submission") consolidated the pendcnt updates to just a single write, neglecting the fact that the error path relied on it getting set to 1 up front (such that the decrement in __end_block_io_op() would actually drop the count to zero, triggering the necessary cleanup actions). Also remove a misleading and a stale (after said commit) comment. CC: stable@vger.kernel.org Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index eaccc222a1dc..477a17c20820 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1001,13 +1001,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, bio->bi_end_io = end_block_io_op; } - /* - * We set it one so that the last submit_bio does not have to call - * atomic_inc. - */ atomic_set(&pending_req->pendcnt, nbio); - - /* Get a reference count for the disk queue and start sending I/O */ blk_start_plug(&plug); for (i = 0; i < nbio; i++) @@ -1035,6 +1029,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, fail_put_bio: for (i = 0; i < nbio; i++) bio_put(biolist[i]); + atomic_set(&pending_req->pendcnt, 1); __end_block_io_op(pending_req, -EINVAL); msleep(1); /* back off a bit */ return -EIO; -- cgit v1.2.3 From 29d0b218c87ace1078e08bb32c2e72fc96fa3db3 Mon Sep 17 00:00:00 2001 From: Mihnea Dobrescu-Balaur Date: Mon, 11 Mar 2013 13:23:36 +0200 Subject: xen-blkfront: replace kmalloc and then memcpy with kmemdup The benefits are: * code is cleaner * kmemdup adds additional debugging info useful for tracking the real place where memory was allocated (CONFIG_DEBUG_SLAB). Signed-off-by: Mihnea Dobrescu-Balaur Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index c3dae2e0f290..962064487ef7 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1203,11 +1203,10 @@ static int blkif_recover(struct blkfront_info *info) int j; /* Stage 1: Make a safe copy of the shadow state. */ - copy = kmalloc(sizeof(info->shadow), + copy = kmemdup(info->shadow, sizeof(info->shadow), GFP_NOIO | __GFP_REPEAT | __GFP_HIGH); if (!copy) return -ENOMEM; - memcpy(copy, info->shadow, sizeof(info->shadow)); /* Stage 2: Set up free list. */ memset(&info->shadow, 0, sizeof(info->shadow)); -- cgit v1.2.3 From ac534ff2d5508bdff1358a55d88053da729ff46b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 15 Mar 2013 09:16:29 -0400 Subject: nfsd: fix startup order in nfsd_reply_cache_init If we end up doing "goto out_nomem" in this function, we'll call nfsd_reply_cache_shutdown. That will attempt to walk the LRU list and free entries, but that list may not be initialized yet if the server is starting up for the first time. It's also possible for the shrinker to kick in before we've initialized the LRU list. Rearrange the initialization so that the LRU list_head and cache size are initialized before doing any of the allocations that might fail. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfscache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 18509bd6f587..ca05f6dc3544 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -119,6 +119,10 @@ nfsd_reply_cache_free(struct svc_cacherep *rp) int nfsd_reply_cache_init(void) { + INIT_LIST_HEAD(&lru_head); + max_drc_entries = nfsd_cache_size_limit(); + num_drc_entries = 0; + register_shrinker(&nfsd_reply_cache_shrinker); drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep), 0, 0, NULL); @@ -129,10 +133,6 @@ int nfsd_reply_cache_init(void) if (!cache_hash) goto out_nomem; - INIT_LIST_HEAD(&lru_head); - max_drc_entries = nfsd_cache_size_limit(); - num_drc_entries = 0; - return 0; out_nomem: printk(KERN_ERR "nfsd: failed to allocate reply cache\n"); -- cgit v1.2.3 From 27ca0391fb717eecb9b9ca29ad4b9e8d7a84aba5 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sat, 9 Mar 2013 22:19:35 +0100 Subject: staging: zcache: fix typo "64_BIT" Signed-off-by: Paul Bolle Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zcache/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig index 73582705e8c5..5c3714530961 100644 --- a/drivers/staging/zcache/Kconfig +++ b/drivers/staging/zcache/Kconfig @@ -15,7 +15,7 @@ config RAMSTER depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE=y depends on NET # must ensure struct page is 8-byte aligned - select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT + select HAVE_ALIGNED_STRUCT_PAGE if !64BIT default n help RAMster allows RAM on other machines in a cluster to be utilized -- cgit v1.2.3 From e71918ea66121985f287c0c3d0efa9c4c35da7fa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 14 Mar 2013 17:56:44 -0300 Subject: [media] ir: IR_RX51 only works on OMAP2 This driver can be enabled on OMAP1 at the moment, which breaks allyesconfig for that platform. Let's mark it OMAP2PLUS-only in Kconfig, since that is the only thing it builds on. Signed-off-by: Arnd Bergmann Acked-by: Timo Kokkonen Acked-by: Tony Lindgren Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 19f3563c61da..5a79c333d45e 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -291,7 +291,7 @@ config IR_TTUSBIR config IR_RX51 tristate "Nokia N900 IR transmitter diode" - depends on OMAP_DM_TIMER && LIRC && !ARCH_MULTIPLATFORM + depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM ---help--- Say Y or M here if you want to enable support for the IR transmitter diode built in the Nokia N900 (RX51) device. -- cgit v1.2.3 From cf2e39429c245245db889fffdfbdf3f889a6cb22 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 9 Mar 2013 23:25:06 +0200 Subject: ipvs: fix sctp chunk length order Fix wrong but non-fatal access to chunk length. sch->length should be in network order, next chunk should be aligned to 4 bytes. Problem noticed in sparse output. Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_proto_sctp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index ae8ec6f27688..cd1d7298f7ba 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -906,7 +906,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, sctp_chunkhdr_t _sctpch, *sch; unsigned char chunk_type; int event, next_state; - int ihl; + int ihl, cofs; #ifdef CONFIG_IP_VS_IPV6 ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr); @@ -914,8 +914,8 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, ihl = ip_hdrlen(skb); #endif - sch = skb_header_pointer(skb, ihl + sizeof(sctp_sctphdr_t), - sizeof(_sctpch), &_sctpch); + cofs = ihl + sizeof(sctp_sctphdr_t); + sch = skb_header_pointer(skb, cofs, sizeof(_sctpch), &_sctpch); if (sch == NULL) return; @@ -933,10 +933,12 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, */ if ((sch->type == SCTP_CID_COOKIE_ECHO) || (sch->type == SCTP_CID_COOKIE_ACK)) { - sch = skb_header_pointer(skb, (ihl + sizeof(sctp_sctphdr_t) + - sch->length), sizeof(_sctpch), &_sctpch); - if (sch) { - if (sch->type == SCTP_CID_ABORT) + int clen = ntohs(sch->length); + + if (clen >= sizeof(sctp_chunkhdr_t)) { + sch = skb_header_pointer(skb, cofs + ALIGN(clen, 4), + sizeof(_sctpch), &_sctpch); + if (sch && sch->type == SCTP_CID_ABORT) chunk_type = sch->type; } } -- cgit v1.2.3 From 6a15075eced2d780fa6c5d83682410f47f2e800b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 18 Mar 2013 19:24:02 +0100 Subject: ARM: video: mxs: Fix mxsfb misconfiguring VDCTRL0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue fixed by this patch manifests only then using X11 with mxsfb driver. The X11 will display either shifted image or otherwise distorted image on the LCD. The problem is that the X11 tries to reconfigure the framebuffer and along the way calls fb_ops.fb_set_par() with X11's desired configuration values. The field of particular interest is fb_info->var.sync which contains non-standard values if configured by kernel. These are either FB_SYNC_DATA_ENABLE_HIGH_ACT, FB_SYNC_DOTCLK_FAILING_ACT or both, depending on the platform configuration. Both of these values are defined in the include/linux/mxsfb.h file. The driver interprets these values and configures the LCD controller accordingly. Yet X11 only has access to the standard values for this field defined in include/uapi/linux/fb.h and thus, unlike kernel, omits these special values. This results in distorted image on the LCD. This patch moves these non-standard values into new field of the mxsfb_platform_data structure so the driver can in turn check this field instead of the video mode field for these specific portions. Moreover, this patch prefixes these values with MXSFB_SYNC_ prefix instead of FB_SYNC_ prefix to prevent confusion of subsequent users. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Linux ARM Cc: Linux FBDEV Cc: Lothar Waßmann Cc: Sascha Hauer Tested-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-mxs/mach-mxs.c | 24 ++++++++++++------------ drivers/video/mxsfb.c | 7 +++++-- include/linux/mxsfb.h | 7 +++++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 3218f1f2c0e0..e7b781d3788f 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -41,8 +41,6 @@ static struct fb_videomode mx23evk_video_modes[] = { .lower_margin = 4, .hsync_len = 1, .vsync_len = 1, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, }, }; @@ -59,8 +57,6 @@ static struct fb_videomode mx28evk_video_modes[] = { .lower_margin = 10, .hsync_len = 10, .vsync_len = 10, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, }, }; @@ -77,7 +73,6 @@ static struct fb_videomode m28evk_video_modes[] = { .lower_margin = 45, .hsync_len = 1, .vsync_len = 1, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT, }, }; @@ -94,9 +89,7 @@ static struct fb_videomode apx4devkit_video_modes[] = { .lower_margin = 13, .hsync_len = 48, .vsync_len = 3, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | - FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, }, }; @@ -113,9 +106,7 @@ static struct fb_videomode apf28dev_video_modes[] = { .lower_margin = 0x15, .hsync_len = 64, .vsync_len = 4, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | - FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, }, }; @@ -132,7 +123,6 @@ static struct fb_videomode cfa10049_video_modes[] = { .lower_margin = 2, .hsync_len = 15, .vsync_len = 15, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT }, }; @@ -259,6 +249,8 @@ static void __init imx23_evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } static inline void enable_clk_enet_out(void) @@ -278,6 +270,8 @@ static void __init imx28_evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); } @@ -297,6 +291,7 @@ static void __init m28evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes); mxsfb_pdata.default_bpp = 16; mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; } static void __init sc_sps1_init(void) @@ -322,6 +317,8 @@ static void __init apx4devkit_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } #define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0) @@ -407,6 +404,7 @@ static void __init cfa10049_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(cfa10049_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; } static void __init cfa10037_init(void) @@ -423,6 +421,8 @@ static void __init apf28_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(apf28dev_video_modes); mxsfb_pdata.default_bpp = 16; mxsfb_pdata.ld_intf_width = STMLCDIF_16BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } static void __init mxs_machine_init(void) diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 755556ca5b2d..45169cbaba6e 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -169,6 +169,7 @@ struct mxsfb_info { unsigned dotclk_delay; const struct mxsfb_devdata *devdata; int mapped; + u32 sync; }; #define mxsfb_is_v3(host) (host->devdata->ipversion == 3) @@ -456,9 +457,9 @@ static int mxsfb_set_par(struct fb_info *fb_info) vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT) vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; - if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT) + if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT) vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; - if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT) + if (host->sync & MXSFB_SYNC_DOTCLK_FAILING_ACT) vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING; writel(vdctrl0, host->base + LCDC_VDCTRL0); @@ -861,6 +862,8 @@ static int mxsfb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&fb_info->modelist); + host->sync = pdata->sync; + ret = mxsfb_init_fbinfo(host); if (ret != 0) goto error_init_fb; diff --git a/include/linux/mxsfb.h b/include/linux/mxsfb.h index f14943d55315..f80af8674342 100644 --- a/include/linux/mxsfb.h +++ b/include/linux/mxsfb.h @@ -24,8 +24,8 @@ #define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */ #define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */ -#define FB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) -#define FB_SYNC_DOTCLK_FAILING_ACT (1 << 7) /* failing/negtive edge sampling */ +#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) +#define MXSFB_SYNC_DOTCLK_FAILING_ACT (1 << 7) /* failing/negtive edge sampling */ struct mxsfb_platform_data { struct fb_videomode *mode_list; @@ -44,6 +44,9 @@ struct mxsfb_platform_data { * allocated. If specified,fb_size must also be specified. * fb_phys must be unused by Linux. */ + u32 sync; /* sync mask, contains MXSFB specifics not + * carried in fb_info->var.sync + */ }; #endif /* __LINUX_MXSFB_H */ -- cgit v1.2.3 From 287939a3690c8da6fd3310d7593ff0448cb9447c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 13 Mar 2013 10:52:49 +0800 Subject: ARM: imx: add dependency check for DEBUG_IMX_UART_PORT While adding i.MX DEBUG_LL selection, commit f8c95fe (ARM: imx: support DEBUG_LL uart port selection for all i.MX SoCs) leaves Kconfig symbol DEBUG_IMX_UART_PORT there without any dependency check. This results in that everyone gets the symbol in their config, which is someting undesirable. Add "depends on ARCH_MXC" for the symbol to prevent that. Reported-by: Karl Beldan Signed-off-by: Shawn Guo --- arch/arm/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index ecfcdba2d17c..9b31f4311ea2 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -495,6 +495,7 @@ config DEBUG_IMX_UART_PORT DEBUG_IMX53_UART || \ DEBUG_IMX6Q_UART default 1 + depends on ARCH_MXC help Choose UART port on which kernel low-level debug messages should be output. -- cgit v1.2.3 From 2105fd550ca7dbdd490934f487852c2a399b20cf Mon Sep 17 00:00:00 2001 From: Pierrick Hascoet Date: Mon, 18 Mar 2013 17:04:45 +0100 Subject: arc: fix dma_address assignment during dma_map_sg() Signed-off-by: Pierrick Hascoet Signed-off-by: Vineet Gupta --- arch/arc/include/asm/dma-mapping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h index 31f77aec0823..45b8e0cea176 100644 --- a/arch/arc/include/asm/dma-mapping.h +++ b/arch/arc/include/asm/dma-mapping.h @@ -126,7 +126,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int i; for_each_sg(sg, s, nents, i) - sg->dma_address = dma_map_page(dev, sg_page(s), s->offset, + s->dma_address = dma_map_page(dev, sg_page(s), s->offset, s->length, dir); return nents; -- cgit v1.2.3 From 0c12582fbcdea0cbb0dfd224e1c5f9a8428ffa18 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 9 Mar 2013 23:25:04 +0200 Subject: ipvs: add backup_only flag to avoid loops Dmitry Akindinov is reporting for a problem where SYNs are looping between the master and backup server when the backup server is used as real server in DR mode and has IPVS rules to function as director. Even when the backup function is enabled we continue to forward traffic and schedule new connections when the current master is using the backup server as real server. While this is not a problem for NAT, for DR and TUN method the backup server can not determine if a request comes from client or from director. To avoid such loops add new sysctl flag backup_only. It can be needed for DR/TUN setups that do not need backup and director function at the same time. When the backup function is enabled we stop any forwarding and pass the traffic to the local stack (real server mode). The flag disables the director function when the backup function is enabled. For setups that enable backup function for some virtual services and director function for other virtual services there should be another more complex solution to support DR/TUN mode, may be to assign per-virtual service syncid value, so that we can differentiate the requests. Reported-by: Dmitry Akindinov Tested-by: German Myzovsky Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- Documentation/networking/ipvs-sysctl.txt | 7 +++++++ include/net/ip_vs.h | 12 ++++++++++++ net/netfilter/ipvs/ip_vs_core.c | 12 ++++++++---- net/netfilter/ipvs/ip_vs_ctl.c | 7 +++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index f2a2488f1bf3..9573d0c48c6e 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -15,6 +15,13 @@ amemthresh - INTEGER enabled and the variable is automatically set to 2, otherwise the strategy is disabled and the variable is set to 1. +backup_only - BOOLEAN + 0 - disabled (default) + not 0 - enabled + + If set, disable the director function while the server is + in backup mode to avoid packet loops for DR/TUN methods. + conntrack - BOOLEAN 0 - disabled (default) not 0 - enabled diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 68c69d54d392..fce8e6b66d55 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -976,6 +976,7 @@ struct netns_ipvs { int sysctl_sync_retries; int sysctl_nat_icmp_send; int sysctl_pmtu_disc; + int sysctl_backup_only; /* ip_vs_lblc */ int sysctl_lblc_expiration; @@ -1067,6 +1068,12 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs) return ipvs->sysctl_pmtu_disc; } +static inline int sysctl_backup_only(struct netns_ipvs *ipvs) +{ + return ipvs->sync_state & IP_VS_STATE_BACKUP && + ipvs->sysctl_backup_only; +} + #else static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs) @@ -1114,6 +1121,11 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs) return 1; } +static inline int sysctl_backup_only(struct netns_ipvs *ipvs) +{ + return 0; +} + #endif /* diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 47edf5a40a59..18b4bc55fa3d 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1577,7 +1577,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; ip_vs_fill_iph_skb(af, skb, &iph); @@ -1654,7 +1655,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); - ipvs = net_ipvs(net); /* Check the server status */ if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { /* the destination server is not available */ @@ -1815,13 +1815,15 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, { int r; struct net *net; + struct netns_ipvs *ipvs; if (ip_hdr(skb)->protocol != IPPROTO_ICMP) return NF_ACCEPT; /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; return ip_vs_in_icmp(skb, &r, hooknum); @@ -1835,6 +1837,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, { int r; struct net *net; + struct netns_ipvs *ipvs; struct ip_vs_iphdr iphdr; ip_vs_fill_iph_skb(AF_INET6, skb, &iphdr); @@ -1843,7 +1846,8 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c68198bf9128..9e2d1cccd1eb 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1808,6 +1808,12 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "backup_only", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #ifdef CONFIG_IP_VS_DEBUG { .procname = "debug_level", @@ -3741,6 +3747,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net) tbl[idx++].data = &ipvs->sysctl_nat_icmp_send; ipvs->sysctl_pmtu_disc = 1; tbl[idx++].data = &ipvs->sysctl_pmtu_disc; + tbl[idx++].data = &ipvs->sysctl_backup_only; ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl); -- cgit v1.2.3 From bf93ad72cd8cfabe66a7b3d66236a1266d357189 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 9 Mar 2013 23:25:05 +0200 Subject: ipvs: remove extra rcu lock In 3.7 we added code that uses ipv4_update_pmtu but after commit c5ae7d4192 (ipv4: must use rcu protection while calling fib_lookup) the RCU lock is not needed. Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 18b4bc55fa3d..61f49d241712 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1394,10 +1394,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) skb_reset_network_header(skb); IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu); - rcu_read_lock(); ipv4_update_pmtu(skb, dev_net(skb->dev), mtu, 0, 0, 0, 0); - rcu_read_unlock(); /* Client uses PMTUD? */ if (!(cih->frag_off & htons(IP_DF))) goto ignore_ipip; -- cgit v1.2.3 From 217fd5e709f029c125a9d39de5f13387407f131a Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Mar 2013 17:49:33 +0100 Subject: xen-blkback: fix foreach_grant_safe to handle empty lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may use foreach_grant_safe in the future with empty lists, so make sure we can handle them. Signed-off-by: Roger Pau Monné Cc: xen-devel@lists.xen.org Cc: Konrad Rzeszutek Wilk Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 477a17c20820..2cf8381a1c6e 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -164,7 +164,7 @@ static void make_response(struct xen_blkif *blkif, u64 id, #define foreach_grant_safe(pos, n, rbtree, node) \ for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \ - (n) = rb_next(&(pos)->node); \ + (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL; \ &(pos)->node != NULL; \ (pos) = container_of(n, typeof(*(pos)), node), \ (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL) -- cgit v1.2.3 From 155b7edb51430a280f86c1e21b7be308b0d219d4 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Mar 2013 17:49:34 +0100 Subject: xen-blkfront: switch from llist to list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The git commit f84adf4921ae3115502f44ff467b04bf2f88cf04 (xen-blkfront: drop the use of llist_for_each_entry_safe) was a stop-gate to fix a GCC4.1 bug. The appropiate way is to actually use an list instead of using an llist. As such this patch replaces the usage of llist with an list. Since we always manipulate the list while holding the io_lock, there's no need for additional locking (llist used previously is safe to use concurrently without additional locking). Signed-off-by: Roger Pau Monné CC: stable@vger.kernel.org [v1: Redid the git commit description] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 962064487ef7..97324cd18f4b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include @@ -68,7 +68,7 @@ enum blkif_state { struct grant { grant_ref_t gref; unsigned long pfn; - struct llist_node node; + struct list_head node; }; struct blk_shadow { @@ -105,7 +105,7 @@ struct blkfront_info struct work_struct work; struct gnttab_free_callback callback; struct blk_shadow shadow[BLK_RING_SIZE]; - struct llist_head persistent_gnts; + struct list_head persistent_gnts; unsigned int persistent_gnts_c; unsigned long shadow_free; unsigned int feature_flush; @@ -371,10 +371,11 @@ static int blkif_queue_request(struct request *req) lsect = fsect + (sg->length >> 9) - 1; if (info->persistent_gnts_c) { - BUG_ON(llist_empty(&info->persistent_gnts)); - gnt_list_entry = llist_entry( - llist_del_first(&info->persistent_gnts), - struct grant, node); + BUG_ON(list_empty(&info->persistent_gnts)); + gnt_list_entry = list_first_entry( + &info->persistent_gnts, + struct grant, node); + list_del(&gnt_list_entry->node); ref = gnt_list_entry->gref; buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); @@ -790,9 +791,8 @@ static void blkif_restart_queue(struct work_struct *work) static void blkif_free(struct blkfront_info *info, int suspend) { - struct llist_node *all_gnts; - struct grant *persistent_gnt, *tmp; - struct llist_node *n; + struct grant *persistent_gnt; + struct grant *n; /* Prevent new requests being issued until we fix things up. */ spin_lock_irq(&info->io_lock); @@ -804,20 +804,15 @@ static void blkif_free(struct blkfront_info *info, int suspend) /* Remove all persistent grants */ if (info->persistent_gnts_c) { - all_gnts = llist_del_all(&info->persistent_gnts); - persistent_gnt = llist_entry(all_gnts, typeof(*(persistent_gnt)), node); - while (persistent_gnt) { + list_for_each_entry_safe(persistent_gnt, n, + &info->persistent_gnts, node) { + list_del(&persistent_gnt->node); gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); __free_page(pfn_to_page(persistent_gnt->pfn)); - tmp = persistent_gnt; - n = persistent_gnt->node.next; - if (n) - persistent_gnt = llist_entry(n, typeof(*(persistent_gnt)), node); - else - persistent_gnt = NULL; - kfree(tmp); + kfree(persistent_gnt); + info->persistent_gnts_c--; } - info->persistent_gnts_c = 0; + BUG_ON(info->persistent_gnts_c != 0); } /* No more gnttab callback work. */ @@ -875,7 +870,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, } /* Add the persistent grant into the list of free grants */ for (i = 0; i < s->req.u.rw.nr_segments; i++) { - llist_add(&s->grants_used[i]->node, &info->persistent_gnts); + list_add(&s->grants_used[i]->node, &info->persistent_gnts); info->persistent_gnts_c++; } } @@ -1171,7 +1166,7 @@ static int blkfront_probe(struct xenbus_device *dev, spin_lock_init(&info->io_lock); info->xbdev = dev; info->vdevice = vdevice; - init_llist_head(&info->persistent_gnts); + INIT_LIST_HEAD(&info->persistent_gnts); info->persistent_gnts_c = 0; info->connected = BLKIF_STATE_DISCONNECTED; INIT_WORK(&info->work, blkif_restart_queue); -- cgit v1.2.3 From ffb1dabd1eb10c76a1e7af62f75a1aaa8d590b5a Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Mar 2013 17:49:32 +0100 Subject: xen-blkback: don't store dev_bus_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_bus_addr returned in the grant ref map operation is the mfn of the passed page, there's no need to store it in the persistent grant entry, since we can always get it provided that we have the page. This reduces the memory overhead of persistent grants in blkback. While at it, rename the 'seg[i].buf' to be 'seg[i].offset' as it makes much more sense - as we use that value in bio_add_page which as the fourth argument expects the offset. We hadn't used the physical address as part of this at all. Signed-off-by: Roger Pau Monné Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xen.org [v1: s/buf/offset/] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 21 ++++++--------------- drivers/block/xen-blkback/common.h | 1 - 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 2cf8381a1c6e..dd5b2fed97e9 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -442,7 +442,7 @@ int xen_blkif_schedule(void *arg) } struct seg_buf { - unsigned long buf; + unsigned int offset; unsigned int nsec; }; /* @@ -621,30 +621,21 @@ static int xen_blkbk_map(struct blkif_request *req, * If this is a new persistent grant * save the handler */ - persistent_gnts[i]->handle = map[j].handle; - persistent_gnts[i]->dev_bus_addr = - map[j++].dev_bus_addr; + persistent_gnts[i]->handle = map[j++].handle; } pending_handle(pending_req, i) = persistent_gnts[i]->handle; if (ret) continue; - - seg[i].buf = persistent_gnts[i]->dev_bus_addr | - (req->u.rw.seg[i].first_sect << 9); } else { - pending_handle(pending_req, i) = map[j].handle; + pending_handle(pending_req, i) = map[j++].handle; bitmap_set(pending_req->unmap_seg, i, 1); - if (ret) { - j++; + if (ret) continue; - } - - seg[i].buf = map[j++].dev_bus_addr | - (req->u.rw.seg[i].first_sect << 9); } + seg[i].offset = (req->u.rw.seg[i].first_sect << 9); } return ret; } @@ -971,7 +962,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, (bio_add_page(bio, pages[i], seg[i].nsec << 9, - seg[i].buf & ~PAGE_MASK) == 0)) { + seg[i].offset) == 0)) { bio = bio_alloc(GFP_KERNEL, nseg-i); if (unlikely(bio == NULL)) diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index da78346487ae..60103e2517ba 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -187,7 +187,6 @@ struct persistent_gnt { struct page *page; grant_ref_t gnt; grant_handle_t handle; - uint64_t dev_bus_addr; struct rb_node node; }; -- cgit v1.2.3 From 9c1e050caeb4d1250f8ceef1180a8b3d0db6c624 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Mar 2013 17:49:35 +0100 Subject: xen-blkfront: pre-allocate pages for requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents us from having to call alloc_page while we are preparing the request. Since blkfront was calling alloc_page with a spinlock held we used GFP_ATOMIC, which can fail if we are requesting a lot of pages since it is using the emergency memory pools. Allocating all the pages at init prevents us from having to call alloc_page, thus preventing possible failures. Signed-off-by: Roger Pau Monné Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xen.org Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 120 ++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 97324cd18f4b..c64043323399 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -165,6 +165,69 @@ static int add_id_to_freelist(struct blkfront_info *info, return 0; } +static int fill_grant_buffer(struct blkfront_info *info, int num) +{ + struct page *granted_page; + struct grant *gnt_list_entry, *n; + int i = 0; + + while(i < num) { + gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO); + if (!gnt_list_entry) + goto out_of_memory; + + granted_page = alloc_page(GFP_NOIO); + if (!granted_page) { + kfree(gnt_list_entry); + goto out_of_memory; + } + + gnt_list_entry->pfn = page_to_pfn(granted_page); + gnt_list_entry->gref = GRANT_INVALID_REF; + list_add(&gnt_list_entry->node, &info->persistent_gnts); + i++; + } + + return 0; + +out_of_memory: + list_for_each_entry_safe(gnt_list_entry, n, + &info->persistent_gnts, node) { + list_del(&gnt_list_entry->node); + __free_page(pfn_to_page(gnt_list_entry->pfn)); + kfree(gnt_list_entry); + i--; + } + BUG_ON(i != 0); + return -ENOMEM; +} + +static struct grant *get_grant(grant_ref_t *gref_head, + struct blkfront_info *info) +{ + struct grant *gnt_list_entry; + unsigned long buffer_mfn; + + BUG_ON(list_empty(&info->persistent_gnts)); + gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, + node); + list_del(&gnt_list_entry->node); + + if (gnt_list_entry->gref != GRANT_INVALID_REF) { + info->persistent_gnts_c--; + return gnt_list_entry; + } + + /* Assign a gref to this page */ + gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); + BUG_ON(gnt_list_entry->gref == -ENOSPC); + buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); + gnttab_grant_foreign_access_ref(gnt_list_entry->gref, + info->xbdev->otherend_id, + buffer_mfn, 0); + return gnt_list_entry; +} + static const char *op_name(int op) { static const char *const names[] = { @@ -306,7 +369,6 @@ static int blkif_queue_request(struct request *req) */ bool new_persistent_gnts; grant_ref_t gref_head; - struct page *granted_page; struct grant *gnt_list_entry = NULL; struct scatterlist *sg; @@ -370,42 +432,9 @@ static int blkif_queue_request(struct request *req) fsect = sg->offset >> 9; lsect = fsect + (sg->length >> 9) - 1; - if (info->persistent_gnts_c) { - BUG_ON(list_empty(&info->persistent_gnts)); - gnt_list_entry = list_first_entry( - &info->persistent_gnts, - struct grant, node); - list_del(&gnt_list_entry->node); - - ref = gnt_list_entry->gref; - buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); - info->persistent_gnts_c--; - } else { - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); - - gnt_list_entry = - kmalloc(sizeof(struct grant), - GFP_ATOMIC); - if (!gnt_list_entry) - return -ENOMEM; - - granted_page = alloc_page(GFP_ATOMIC); - if (!granted_page) { - kfree(gnt_list_entry); - return -ENOMEM; - } - - gnt_list_entry->pfn = - page_to_pfn(granted_page); - gnt_list_entry->gref = ref; - - buffer_mfn = pfn_to_mfn(page_to_pfn( - granted_page)); - gnttab_grant_foreign_access_ref(ref, - info->xbdev->otherend_id, - buffer_mfn, 0); - } + gnt_list_entry = get_grant(&gref_head, info); + ref = gnt_list_entry->gref; + buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); info->shadow[id].grants_used[i] = gnt_list_entry; @@ -803,17 +832,20 @@ static void blkif_free(struct blkfront_info *info, int suspend) blk_stop_queue(info->rq); /* Remove all persistent grants */ - if (info->persistent_gnts_c) { + if (!list_empty(&info->persistent_gnts)) { list_for_each_entry_safe(persistent_gnt, n, &info->persistent_gnts, node) { list_del(&persistent_gnt->node); - gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); + if (persistent_gnt->gref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(persistent_gnt->gref, + 0, 0UL); + info->persistent_gnts_c--; + } __free_page(pfn_to_page(persistent_gnt->pfn)); kfree(persistent_gnt); - info->persistent_gnts_c--; } - BUG_ON(info->persistent_gnts_c != 0); } + BUG_ON(info->persistent_gnts_c != 0); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); @@ -1008,6 +1040,12 @@ static int setup_blkring(struct xenbus_device *dev, sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); + /* Allocate memory for grants */ + err = fill_grant_buffer(info, BLK_RING_SIZE * + BLKIF_MAX_SEGMENTS_PER_REQUEST); + if (err) + goto fail; + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); if (err < 0) { free_page((unsigned long)sring); -- cgit v1.2.3 From b1173e316bf2ff3c11f46247417f0f5789a4ea0c Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Mar 2013 17:49:36 +0100 Subject: xen-blkfront: remove frame list from blk_shadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have the frame (pfn of the grant page) stored inside struct grant, so there's no need to keep an aditional list of mapped frames for a specific request. This reduces memory usage in blkfront. Signed-off-by: Roger Pau Monné Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xen.org Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index c64043323399..a894f88762d8 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -74,7 +74,6 @@ struct grant { struct blk_shadow { struct blkif_request req; struct request *request; - unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; @@ -356,7 +355,6 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, static int blkif_queue_request(struct request *req) { struct blkfront_info *info = req->rq_disk->private_data; - unsigned long buffer_mfn; struct blkif_request *ring_req; unsigned long id; unsigned int fsect, lsect; @@ -434,7 +432,6 @@ static int blkif_queue_request(struct request *req) gnt_list_entry = get_grant(&gref_head, info); ref = gnt_list_entry->gref; - buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); info->shadow[id].grants_used[i] = gnt_list_entry; @@ -465,7 +462,6 @@ static int blkif_queue_request(struct request *req) kunmap_atomic(shared_data); } - info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); ring_req->u.rw.seg[i] = (struct blkif_request_segment) { .gref = ref, @@ -1268,7 +1264,7 @@ static int blkif_recover(struct blkfront_info *info) gnttab_grant_foreign_access_ref( req->u.rw.seg[j].gref, info->xbdev->otherend_id, - pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]), + pfn_to_mfn(copy[i].grants_used[j]->pfn), 0); } info->shadow[req->u.rw.id].req = *req; -- cgit v1.2.3 From 63c2b6812f1dc0beda4d6adad0365e048aa693e2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 18 Mar 2013 15:56:10 +0000 Subject: MIPS: Fix code generation for non-DSP capable CPUs Commit 32a7ede (MIPS: dsp: Add assembler support for DSP ASEs) has enabled the use of DSP ASE specific instructions such as rddsp and wrdsp under the idea that all code path that will make use of these two instructions are properly checking for cpu_has_dsp to ensure that the particular CPU we are running on *actually* supports DSP ASE. This commit actually causes the following oops on QEMU Malta emulating a MIPS 24Kc without the DSP ASE implemented: [ 7.960000] Reserved instruction in kernel [ 7.960000] Cpu 0 [ 7.960000] $ 0 : 00000000 00000000 00000014 00000005 [ 7.960000] $ 4 : 8fc2de48 00000001 00000000 8f59ddb0 [ 7.960000] $ 8 : 8f5ceec4 00000018 00000c00 00800000 [ 7.960000] $12 : 00000100 00000200 00000000 00457b84 [ 7.960000] $16 : 00000000 8fc2ba78 8f4ec980 00000001 [ 7.960000] $20 : 80418f90 00000000 00000000 000002dd [ 7.960000] $24 : 0000009c 7730d7b8 [ 7.960000] $28 : 8f59c000 8f59dd38 00000001 80104248 [ 7.960000] Hi : 0000001d [ 7.960000] Lo : 0000000b [ 7.960000] epc : 801041ec thread_saved_pc+0x2c/0x38 [ 7.960000] Not tainted [ 7.960000] ra : 80104248 get_wchan+0x48/0xac [ 7.960000] Status: 1000b703 KERNEL EXL IE [ 7.960000] Cause : 10800028 [ 7.960000] PrId : 00019300 (MIPS 24Kc) [ 7.960000] Modules linked in: [ 7.960000] Process killall (pid: 1574, threadinfo=8f59c000, task=8fd14558, tls=773aa440) [ 7.960000] Stack : 8fc2ba78 8012b008 0000000c 0000001d 00000000 00000000 8f58a380 8f58a380 8fc2ba78 80202668 8f59de78 8f468600 8f59de28 801b2a3c 8f59df00 8f98ba20 74696e69 8f468600 8f59de28 801b7308 0081c007 00000000 00000000 00000000 00000000 00000000 00000000 00000000 8fc2bbb4 00000001 0000001d 0000000b 77f038cc 7fe80648 ffffffff ffffffff 00000000 00000001 0016e000 00000000 ... [ 7.960000] Call Trace: [ 7.960000] [<801041ec>] thread_saved_pc+0x2c/0x38 [ 7.960000] [<80104248>] get_wchan+0x48/0xac The disassembly of thread_saved_pc points to the following: 000006d0 : 6d0: 8c820208 lw v0,520(a0) 6d4: 3c030000 lui v1,0x0 6d8: 24630000 addiu v1,v1,0 6dc: 10430008 beq v0,v1,700 6e0: 00000000 nop 6e4: 3c020000 lui v0,0x0 6e8: 8c43000c lw v1,12(v0) 6ec: 04620004 bltzl v1,700 6f0: 00001021 move v0,zero 6f4: 8c840200 lw a0,512(a0) 6f8: 00031080 sll v0,v1,0x2 6fc: 7c44100a lwx v0,a0(v0) <------------ 700: 03e00008 jr ra 704: 00000000 nop If we specifically disable -mdsp/-mdspr2 for arch/mips/kernel/process.o, we get the following (non-crashing) assembly: 00000708 : 708: 8c820208 lw v0,520(a0) 70c: 3c030000 lui v1,0x0 710: 24630000 addiu v1,v1,0 714: 10430009 beq v0,v1,73c 718: 00000000 nop 71c: 3c020000 lui v0,0x0 720: 8c42000c lw v0,12(v0) 724: 04420005 bltzl v0,73c 728: 00001021 move v0,zero 72c: 8c830200 lw v1,512(a0) 730: 00021080 sll v0,v0,0x2 734: 00431021 addu v0,v0,v1 738: 8c420000 lw v0,0(v0) 73c: 03e00008 jr ra 740: 00000000 nop The specific line that leads a different assembly being produced is: unsigned long thread_saved_pc(struct task_struct *tsk) ... return ((unsigned long *)t->reg29)[schedule_mfi.pc_offset]; <--- The problem here is that the compiler was given the right to use DSP instructions with the -mdsp / -mdspr2 command-line switches and performed some optimization for us and used DSP ASE instructions where we are not checking that the running CPU actually supports DSP ASE. This patch fixes the issue by partially reverting commit 32a7ede for arch/mips/kernel/Makefile in order to remove the -mdsp / -mdspr2 compiler command-line switches such that we are now guaranteed that the compiler will not optimize using DSP ASE reserved instructions. We also need to fixup the rddsp/wrdsp and m{t,h}{hi,lo}{0,1,2,3} macros in arch/mips/include/asm/mipsregs.h to tell the assembler that we are going to explicitely use DSP ASE reserved instructions. The comment in arch/mips/kernel/Makefile is also updated to reflect that. Signed-off-by: Florian Fainelli Acked-by: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: blogic@openwrt.org Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 209 +++++++++++++++++++++++++++++++++++---- arch/mips/kernel/Makefile | 25 ++--- 2 files changed, 196 insertions(+), 38 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 12b70c25906a..0da44d422f5b 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1166,7 +1166,10 @@ do { \ unsigned int __dspctl; \ \ __asm__ __volatile__( \ + " .set push \n" \ + " .set dsp \n" \ " rddsp %0, %x1 \n" \ + " .set pop \n" \ : "=r" (__dspctl) \ : "i" (mask)); \ __dspctl; \ @@ -1175,30 +1178,198 @@ do { \ #define wrdsp(val, mask) \ do { \ __asm__ __volatile__( \ + " .set push \n" \ + " .set dsp \n" \ " wrdsp %0, %x1 \n" \ + " .set pop \n" \ : \ : "r" (val), "i" (mask)); \ } while (0) -#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;}) -#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;}) -#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;}) -#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;}) - -#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;}) -#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;}) -#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;}) -#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;}) - -#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x)) -#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x)) -#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x)) -#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x)) - -#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x)) -#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x)) -#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x)) -#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x)) +#define mflo0() \ +({ \ + long mflo0; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mflo %0, $ac0 \n" \ + " .set pop \n" \ + : "=r" (mflo0)); \ + mflo0; \ +}) + +#define mflo1() \ +({ \ + long mflo1; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mflo %0, $ac1 \n" \ + " .set pop \n" \ + : "=r" (mflo1)); \ + mflo1; \ +}) + +#define mflo2() \ +({ \ + long mflo2; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mflo %0, $ac2 \n" \ + " .set pop \n" \ + : "=r" (mflo2)); \ + mflo2; \ +}) + +#define mflo3() \ +({ \ + long mflo3; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mflo %0, $ac3 \n" \ + " .set pop \n" \ + : "=r" (mflo3)); \ + mflo3; \ +}) + +#define mfhi0() \ +({ \ + long mfhi0; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mfhi %0, $ac0 \n" \ + " .set pop \n" \ + : "=r" (mfhi0)); \ + mfhi0; \ +}) + +#define mfhi1() \ +({ \ + long mfhi1; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mfhi %0, $ac1 \n" \ + " .set pop \n" \ + : "=r" (mfhi1)); \ + mfhi1; \ +}) + +#define mfhi2() \ +({ \ + long mfhi2; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mfhi %0, $ac2 \n" \ + " .set pop \n" \ + : "=r" (mfhi2)); \ + mfhi2; \ +}) + +#define mfhi3() \ +({ \ + long mfhi3; \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mfhi %0, $ac3 \n" \ + " .set pop \n" \ + : "=r" (mfhi3)); \ + mfhi3; \ +}) + + +#define mtlo0(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mtlo %0, $ac0 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mtlo1(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mtlo %0, $ac1 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mtlo2(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mtlo %0, $ac2 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mtlo3(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mtlo %0, $ac3 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mthi0(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mthi %0, $ac0 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mthi1(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mthi %0, $ac1 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mthi2(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mthi %0, $ac2 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) + +#define mthi3(x) \ +({ \ + __asm__( \ + " .set push \n" \ + " .set dsp \n" \ + " mthi %0, $ac3 \n" \ + " .set pop \n" \ + : \ + : "r" (x)); \ +}) #else diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index f81d98f6184c..de75fb50562b 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -100,29 +100,16 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o # -# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe -# to enable DSP assembler support here even if the MIPS Release 2 CPU we -# are targetting does not support DSP because all code-paths making use of -# it properly check that the running CPU *actually does* support these -# instructions. +# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not +# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches +# here because the compiler may use DSP ASE instructions (such as lwx) in +# code paths where we cannot check that the CPU we are running on supports it. +# Proper abstraction using HAVE_AS_DSP and macros is done in +# arch/mips/include/asm/mipsregs.h. # ifeq ($(CONFIG_CPU_MIPSR2), y) CFLAGS_DSP = -DHAVE_AS_DSP -# -# Check if assembler supports DSP ASE -# -ifeq ($(call cc-option-yn,-mdsp), y) -CFLAGS_DSP += -mdsp -endif - -# -# Check if assembler supports DSP ASE Rev2 -# -ifeq ($(call cc-option-yn,-mdspr2), y) -CFLAGS_DSP += -mdspr2 -endif - CFLAGS_signal.o = $(CFLAGS_DSP) CFLAGS_signal32.o = $(CFLAGS_DSP) CFLAGS_process.o = $(CFLAGS_DSP) -- cgit v1.2.3 From 97367519d7dac94de566796f034d5f72cbc671f7 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 19 Mar 2013 13:08:27 +0000 Subject: MIPS: BCM63XX: Make nvram checksum failure non fatal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some vendors modify the nvram layout moving the checksum to a different place or dropping entirely, so reduce the checksum failure to a warning. Reported-by: Álvaro Fernández Rojas Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: John Crispin Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/boards/board_bcm963xx.c | 5 +---- arch/mips/bcm63xx/nvram.c | 7 +++---- arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h | 4 +--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index ed1949c29508..9aa7d44898ed 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -745,10 +745,7 @@ void __init board_prom_init(void) strcpy(cfe_version, "unknown"); printk(KERN_INFO PFX "CFE version: %s\n", cfe_version); - if (bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET)) { - printk(KERN_ERR PFX "invalid nvram checksum\n"); - return; - } + bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET); board_name = bcm63xx_nvram_get_name(); /* find board by name */ diff --git a/arch/mips/bcm63xx/nvram.c b/arch/mips/bcm63xx/nvram.c index 620611680839..a4b8864f9307 100644 --- a/arch/mips/bcm63xx/nvram.c +++ b/arch/mips/bcm63xx/nvram.c @@ -38,7 +38,7 @@ struct bcm963xx_nvram { static struct bcm963xx_nvram nvram; static int mac_addr_used; -int __init bcm63xx_nvram_init(void *addr) +void __init bcm63xx_nvram_init(void *addr) { unsigned int check_len; u32 crc, expected_crc; @@ -60,9 +60,8 @@ int __init bcm63xx_nvram_init(void *addr) crc = crc32_le(~0, (u8 *)&nvram, check_len); if (crc != expected_crc) - return -EINVAL; - - return 0; + pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n", + expected_crc, crc); } u8 *bcm63xx_nvram_get_name(void) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h index 62d6a3b4d3b7..4e0b6bc1165e 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h @@ -9,10 +9,8 @@ * * Initialized the local nvram copy from the target address and checks * its checksum. - * - * Returns 0 on success. */ -int __init bcm63xx_nvram_init(void *nvram); +void bcm63xx_nvram_init(void *nvram); /** * bcm63xx_nvram_get_name() - returns the board name according to nvram -- cgit v1.2.3 From 1762c5ab7ce5f482aafaf9b6a721e41f073ae3cb Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 19 Mar 2013 13:20:19 +0000 Subject: Revert "MIPS: BCM63XX: Call board_register_device from device_initcall()" This commit causes a race between PCI scan and SSB fallback SPROM handler registration, causing the wifi to not work on slower systems. The only subsystem touched from board_register_devices is platform device registration, which is safe as an arch init call. This reverts commit d64ed7ada2f689d2c62af1892ca55e47d3653e36 [MIPS: BCM63XX: Call board_register_device from device_initcall()]. Signed-off-by: Jonas Gorski To: linux-mips@linux-mips.org Cc: John Crispin Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index 314231be788c..35e18e98beb9 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -157,4 +157,4 @@ int __init bcm63xx_register_devices(void) return board_register_devices(); } -device_initcall(bcm63xx_register_devices); +arch_initcall(bcm63xx_register_devices); -- cgit v1.2.3 From 2a1486981c1317dc4f4aad568f2cc6e49dfb8c82 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 19 Mar 2013 14:00:53 +0000 Subject: Fix breakage in MIPS siginfo handling MIPS's siginfo handling has been broken since this commit: commit 574c4866e33d648520a8bd5bf6f573ea6e554e88 Author: Al Viro Date: Sun Nov 25 22:24:19 2012 -0500 consolidate kernel-side struct sigaction declarations for 64-bit BE MIPS CPUs. The UAPI variant looks like this: struct sigaction { unsigned int sa_flags; __sighandler_t sa_handler; sigset_t sa_mask; }; but the core kernel's variant looks like this: struct sigaction { #ifndef __ARCH_HAS_ODD_SIGACTION __sighandler_t sa_handler; unsigned long sa_flags; #else unsigned long sa_flags; __sighandler_t sa_handler; #endif #ifdef __ARCH_HAS_SA_RESTORER __sigrestore_t sa_restorer; #endif sigset_t sa_mask; }; The problem is that sa_flags has been changed from an unsigned int to an unsigned long. Fix this by making sa_flags unsigned int if __ARCH_HAS_ODD_SIGACTION is defined. Whilst we're at it, rename __ARCH_HAS_ODD_SIGACTION to __ARCH_HAS_IRIX_SIGACTION. Signed-off-by: David Howells Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Acked-by: Al Viro Signed-off-by: Ralf Baechle --- arch/mips/include/asm/signal.h | 2 +- include/linux/compat.h | 4 ++-- include/linux/signal.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 197f6367c201..8efe5a9e2c3e 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -21,6 +21,6 @@ #include #include -#define __ARCH_HAS_ODD_SIGACTION +#define __ARCH_HAS_IRIX_SIGACTION #endif /* _ASM_SIGNAL_H */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 76a87fb57ac2..377cd8c3395e 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -141,11 +141,11 @@ typedef struct { } compat_sigset_t; struct compat_sigaction { -#ifndef __ARCH_HAS_ODD_SIGACTION +#ifndef __ARCH_HAS_IRIX_SIGACTION compat_uptr_t sa_handler; compat_ulong_t sa_flags; #else - compat_ulong_t sa_flags; + compat_uint_t sa_flags; compat_uptr_t sa_handler; #endif #ifdef __ARCH_HAS_SA_RESTORER diff --git a/include/linux/signal.h b/include/linux/signal.h index a2dcb94ea49d..9475c5cb28bc 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -250,11 +250,11 @@ extern int show_unhandled_signals; extern int sigsuspend(sigset_t *); struct sigaction { -#ifndef __ARCH_HAS_ODD_SIGACTION +#ifndef __ARCH_HAS_IRIX_SIGACTION __sighandler_t sa_handler; unsigned long sa_flags; #else - unsigned long sa_flags; + unsigned int sa_flags; __sighandler_t sa_handler; #endif #ifdef __ARCH_HAS_SA_RESTORER -- cgit v1.2.3 From 3dd6664fac7e6041bfc8756ae9e8c78f59108cd9 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 19 Mar 2013 13:09:59 +0000 Subject: netfilter: remove unused "config IP_NF_QUEUE" Kconfig symbol IP_NF_QUEUE is unused since commit d16cf20e2f2f13411eece7f7fb72c17d141c4a84 ("netfilter: remove ip_queue support"). Let's remove it too. Signed-off-by: Paul Bolle Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/Kconfig | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index ce2d43e1f09f..0d755c50994b 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -36,19 +36,6 @@ config NF_CONNTRACK_PROC_COMPAT If unsure, say Y. -config IP_NF_QUEUE - tristate "IP Userspace queueing via NETLINK (OBSOLETE)" - depends on NETFILTER_ADVANCED - help - Netfilter has the ability to queue packets to user space: the - netlink device can be used to access them using this driver. - - This option enables the old IPv4-only "ip_queue" implementation - which has been obsoleted by the new "nfnetlink_queue" code (see - CONFIG_NETFILTER_NETLINK_QUEUE). - - To compile it as a module, choose M here. If unsure, say N. - config IP_NF_IPTABLES tristate "IP tables support (required for filtering/masq/NAT)" default m if NETFILTER_ADVANCED=n -- cgit v1.2.3 From b7d44d9487a11e835de10908f4ab30b4290c0b7f Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Wed, 20 Mar 2013 11:28:51 +1030 Subject: hw_random: free rng_buffer at module exit rng-core module allocates rng_buffer by kmalloc() since commit f7f154f1246ccc5a0a7e9ce50932627d60a0c878. But this buffer won't be freed and there is a memory leak possibility at module exit. Signed-off-by: Satoru Takeuchi Signed-off-by: Rusty Russell --- drivers/char/hw_random/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 69ae5972713c..a0f7724852eb 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -380,6 +380,15 @@ void hwrng_unregister(struct hwrng *rng) } EXPORT_SYMBOL_GPL(hwrng_unregister); +static void __exit hwrng_exit(void) +{ + mutex_lock(&rng_mutex); + BUG_ON(current_rng); + kfree(rng_buffer); + mutex_unlock(&rng_mutex); +} + +module_exit(hwrng_exit); MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From c83a9d5e425d4678b05ca058fec6254f18601474 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 19 Mar 2013 08:04:44 -0700 Subject: x86-32, microcode_intel_early: Fix crash with CONFIG_DEBUG_VIRTUAL In 32-bit, __pa_symbol() in CONFIG_DEBUG_VIRTUAL accesses kernel data (e.g. max_low_pfn) that not only hasn't been setup yet in such early boot phase, but since we are in linear mode, cannot even be detected as uninitialized. Thus, use __pa_nodebug() rather than __pa_symbol() to get a global symbol's physical address. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1363705484-27645-1-git-send-email-fenghua.yu@intel.com Reported-and-tested-by: Tetsuo Handa Signed-off-by: H. Peter Anvin --- arch/x86/kernel/microcode_intel_early.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c index 7890bc838952..5992ee8086b7 100644 --- a/arch/x86/kernel/microcode_intel_early.c +++ b/arch/x86/kernel/microcode_intel_early.c @@ -90,13 +90,13 @@ microcode_phys(struct microcode_intel **mc_saved_tmp, struct microcode_intel ***mc_saved; mc_saved = (struct microcode_intel ***) - __pa_symbol(&mc_saved_data->mc_saved); + __pa_nodebug(&mc_saved_data->mc_saved); for (i = 0; i < mc_saved_data->mc_saved_count; i++) { struct microcode_intel *p; p = *(struct microcode_intel **) - __pa(mc_saved_data->mc_saved + i); - mc_saved_tmp[i] = (struct microcode_intel *)__pa(p); + __pa_nodebug(mc_saved_data->mc_saved + i); + mc_saved_tmp[i] = (struct microcode_intel *)__pa_nodebug(p); } } #endif @@ -562,7 +562,7 @@ scan_microcode(unsigned long start, unsigned long end, struct cpio_data cd; long offset = 0; #ifdef CONFIG_X86_32 - char *p = (char *)__pa_symbol(ucode_name); + char *p = (char *)__pa_nodebug(ucode_name); #else char *p = ucode_name; #endif @@ -630,8 +630,8 @@ static void __cpuinit print_ucode(struct ucode_cpu_info *uci) if (mc_intel == NULL) return; - delay_ucode_info_p = (int *)__pa_symbol(&delay_ucode_info); - current_mc_date_p = (int *)__pa_symbol(¤t_mc_date); + delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); + current_mc_date_p = (int *)__pa_nodebug(¤t_mc_date); *delay_ucode_info_p = 1; *current_mc_date_p = mc_intel->hdr.date; @@ -741,15 +741,15 @@ load_ucode_intel_bsp(void) #ifdef CONFIG_X86_32 struct boot_params *boot_params_p; - boot_params_p = (struct boot_params *)__pa_symbol(&boot_params); + boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params); ramdisk_image = boot_params_p->hdr.ramdisk_image; ramdisk_size = boot_params_p->hdr.ramdisk_size; initrd_start_early = ramdisk_image; initrd_end_early = initrd_start_early + ramdisk_size; _load_ucode_intel_bsp( - (struct mc_saved_data *)__pa_symbol(&mc_saved_data), - (unsigned long *)__pa_symbol(&mc_saved_in_initrd), + (struct mc_saved_data *)__pa_nodebug(&mc_saved_data), + (unsigned long *)__pa_nodebug(&mc_saved_in_initrd), initrd_start_early, initrd_end_early, &uci); #else ramdisk_image = boot_params.hdr.ramdisk_image; @@ -772,10 +772,10 @@ void __cpuinit load_ucode_intel_ap(void) unsigned long *initrd_start_p; mc_saved_in_initrd_p = - (unsigned long *)__pa_symbol(mc_saved_in_initrd); - mc_saved_data_p = (struct mc_saved_data *)__pa_symbol(&mc_saved_data); - initrd_start_p = (unsigned long *)__pa_symbol(&initrd_start); - initrd_start_addr = (unsigned long)__pa_symbol(*initrd_start_p); + (unsigned long *)__pa_nodebug(mc_saved_in_initrd); + mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); + initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start); + initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p); #else mc_saved_data_p = &mc_saved_data; mc_saved_in_initrd_p = mc_saved_in_initrd; -- cgit v1.2.3 From 2fb148804fe50639be4c5addb9e28aad0fce1687 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 Mar 2013 02:22:40 -0300 Subject: ASoC: fsl: imx-pcm-fiq: Use 'unsigned int' for period Fix the following warning when building with W=1 option: sound/soc/fsl/imx-pcm-fiq.c: In function 'snd_hrtimer_callback': sound/soc/fsl/imx-pcm-fiq.c:76:12: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 920f945cb2f4..47228c0f929e 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -34,7 +34,7 @@ #include "imx-ssi.h" struct imx_pcm_runtime_data { - int period; + unsigned int period; int periods; unsigned long offset; unsigned long last_offset; -- cgit v1.2.3 From 623766318aeb5f8dee83b2e8926c39cf83568197 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Mar 2013 10:47:12 +0100 Subject: ASoC: omap-mcpdm: Collect link direction configuration under a struct mcpdm_link_config will collect the link direction related configurations like channel masks, FIFO threshold. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index ddfcc1834ff0..6e19f440a28c 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -45,6 +45,11 @@ #define OMAP44XX_MCPDM_L3_BASE 0x49032000 +struct mcpdm_link_config { + u32 link_mask; /* channel mask for the direction */ + u32 threshold; /* FIFO threshold */ +}; + struct omap_mcpdm { struct device *dev; unsigned long phys_base; @@ -53,13 +58,8 @@ struct omap_mcpdm { struct mutex mutex; - /* channel data */ - u32 dn_channels; - u32 up_channels; - - /* McPDM FIFO thresholds */ - u32 dn_threshold; - u32 up_threshold; + /* Playback/Capture configuration */ + struct mcpdm_link_config config[2]; /* McPDM dn offsets for rx1, and 2 channels */ u32 dn_rx_offset; @@ -130,11 +130,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); + u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - ctrl |= mcpdm->dn_channels | mcpdm->up_channels; + ctrl |= link_mask; omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); @@ -148,11 +149,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); + u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels); + ctrl &= ~(link_mask); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); @@ -188,8 +190,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); } - omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold); - omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold); + omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, + mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); + omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, + mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); @@ -296,6 +300,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int stream = substream->stream; struct omap_pcm_dma_data *dma_data; + u32 threshold; int channels; int link_mask = 0; @@ -325,15 +330,16 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, dma_data = snd_soc_dai_get_dma_data(dai, substream); + threshold = mcpdm->config[stream].threshold; /* Configure McPDM channels, and DMA packet size */ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - mcpdm->dn_channels = link_mask << 3; + link_mask <<= 3; dma_data->packet_size = - (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels; + (MCPDM_DN_THRES_MAX - threshold) * channels; } else { - mcpdm->up_channels = link_mask << 0; - dma_data->packet_size = mcpdm->up_threshold * channels; + dma_data->packet_size = threshold * channels; } + mcpdm->config[stream].link_mask = link_mask; return 0; } @@ -380,8 +386,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) } /* Configure McPDM threshold values */ - mcpdm->dn_threshold = 2; - mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3; + mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2; + mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold = + MCPDM_UP_THRES_MAX - 3; return ret; } -- cgit v1.2.3 From 81054b226b76145628670a962674ab312690ab86 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Mar 2013 10:47:13 +0100 Subject: ASoC: omap-mcpdm: Fix for full duplex audio use case Due to HW limitation within OMAP McPDM IP uplink and downlink need to be started at the same time. This causes issues when we have two streams running, for example: arecord | aplay In this case the playback stream would have no channels enabled since at the capture start we are not aware that a playback is going to start. The workaround is to configure the other direction to stereo when the first stream is started. When the second stream is coming we check the new stream's number of channels against the pre-configured channels. If it does not match we stop and restart McPDM to update the configuration. This might result a small pop. If the coming stream is a match we do nothing in the McPDM driver. This workaround can handle most use cases without the need to restart McPDM. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 6e19f440a28c..cd0e2ec90128 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -63,6 +63,9 @@ struct omap_mcpdm { /* McPDM dn offsets for rx1, and 2 channels */ u32 dn_rx_offset; + + /* McPDM needs to be restarted due to runtime reconfiguration */ + bool restart; }; /* @@ -149,7 +152,7 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) { u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; + u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); @@ -287,6 +290,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, if (omap_mcpdm_active(mcpdm)) { omap_mcpdm_stop(mcpdm); omap_mcpdm_close_streams(mcpdm); + mcpdm->config[0].link_mask = 0; + mcpdm->config[1].link_mask = 0; } } @@ -334,11 +339,26 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, /* Configure McPDM channels, and DMA packet size */ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { link_mask <<= 3; + + /* If capture is not running assume a stereo stream to come */ + if (!mcpdm->config[!stream].link_mask) + mcpdm->config[!stream].link_mask = 0x3; + dma_data->packet_size = (MCPDM_DN_THRES_MAX - threshold) * channels; } else { + /* If playback is not running assume a stereo stream to come */ + if (!mcpdm->config[!stream].link_mask) + mcpdm->config[!stream].link_mask = (0x3 << 3); + dma_data->packet_size = threshold * channels; } + + /* Check if we need to restart McPDM with this stream */ + if (mcpdm->config[stream].link_mask && + mcpdm->config[stream].link_mask != link_mask) + mcpdm->restart = true; + mcpdm->config[stream].link_mask = link_mask; return 0; @@ -352,6 +372,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, if (!omap_mcpdm_active(mcpdm)) { omap_mcpdm_start(mcpdm); omap_mcpdm_reg_dump(mcpdm); + } else if (mcpdm->restart) { + omap_mcpdm_stop(mcpdm); + omap_mcpdm_start(mcpdm); + mcpdm->restart = false; + omap_mcpdm_reg_dump(mcpdm); } return 0; -- cgit v1.2.3 From 167b5b93a4d53f29d4fda55f96116f525b2eb3d6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 20 Mar 2013 10:47:14 +0100 Subject: ASoC: omap-mcpdm: Remove leftower define for IO address The IO address is no longer hardwired into the driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index cd0e2ec90128..e1d3998cb0a5 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -43,8 +43,6 @@ #include "omap-mcpdm.h" #include "omap-pcm.h" -#define OMAP44XX_MCPDM_L3_BASE 0x49032000 - struct mcpdm_link_config { u32 link_mask; /* channel mask for the direction */ u32 threshold; /* FIFO threshold */ -- cgit v1.2.3 From 18b97dbe86735502794ba988d4171dc531d8a589 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 18 Mar 2013 18:57:24 +0100 Subject: ASoC: spear_pcm: Staticize non-exported structs Signed-off-by: Lars-Peter Clausen Acked-by: Rajeev Kumar Signed-off-by: Mark Brown --- sound/soc/spear/spear_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 9b76cc5a1148..69803919b838 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -25,7 +25,7 @@ #include #include -struct snd_pcm_hardware spear_pcm_hardware = { +static struct snd_pcm_hardware spear_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), @@ -178,7 +178,7 @@ static int spear_pcm_new(struct snd_card *card, return 0; } -struct snd_soc_platform_driver spear_soc_platform = { +static struct snd_soc_platform_driver spear_soc_platform = { .ops = &spear_pcm_ops, .pcm_new = spear_pcm_new, .pcm_free = spear_pcm_free, -- cgit v1.2.3 From 5830daf8174d7ea8df2621f8dbede3096bb659b5 Mon Sep 17 00:00:00 2001 From: Vikas Sajjan Date: Wed, 27 Feb 2013 16:02:58 +0530 Subject: drm/exynos: modify the compatible string for exynos fimd modified compatible string for exynos4 fimd as "exynos4210-fimd" and exynos5 fimd as "exynos5250-fimd" to stick to the rule that compatible value should be named after first specific SoC model in which this particular IP version was included as discussed at https://patchwork.kernel.org/patch/2144861/ Signed-off-by: Vikas Sajjan Acked-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 36493ce71f9a..549cb7db9c9f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -109,9 +109,9 @@ struct fimd_context { #ifdef CONFIG_OF static const struct of_device_id fimd_driver_dt_match[] = { - { .compatible = "samsung,exynos4-fimd", + { .compatible = "samsung,exynos4210-fimd", .data = &exynos4_fimd_driver_data }, - { .compatible = "samsung,exynos5-fimd", + { .compatible = "samsung,exynos5250-fimd", .data = &exynos5_fimd_driver_data }, {}, }; -- cgit v1.2.3 From 9800935a215ddf278da4860f59b4d29d2f429152 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 2 Mar 2013 15:06:24 +0530 Subject: drm/exynos: Make mixer_check_timing static Fixes the following sparse warning: drivers/gpu/drm/exynos/exynos_mixer.c:821:5: warning: symbol 'mixer_check_timing' was not declared. Should it be static? Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e919aba29b3d..2f4f72f07047 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -818,7 +818,7 @@ static void mixer_win_disable(void *ctx, int win) mixer_ctx->win_data[win].enabled = false; } -int mixer_check_timing(void *ctx, struct fb_videomode *timing) +static int mixer_check_timing(void *ctx, struct fb_videomode *timing) { struct mixer_context *mixer_ctx = ctx; u32 w, h; -- cgit v1.2.3 From 0f10cf1463c6fc02a9e85bf098ef3c215d94b1e3 Mon Sep 17 00:00:00 2001 From: Leela Krishna Amudala Date: Thu, 7 Mar 2013 23:28:52 -0500 Subject: drm/exynos: fimd: calculate the correct address offset Calculate the correct address offset values for alpha and color key control registers based on exynos4 and exynos5 user manuals. Also remove VIDOSD_C_SIZE_W0 macro and fix comments about registers for size and alpha. Signed-off-by: Leela Krishna Amudala Acked-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 549cb7db9c9f..98cc14725ba9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -38,11 +38,12 @@ /* position control register for hardware window 0, 2 ~ 4.*/ #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) -/* size control register for hardware window 0. */ -#define VIDOSD_C_SIZE_W0 (VIDOSD_BASE + 0x08) -/* alpha control register for hardware window 1 ~ 4. */ -#define VIDOSD_C(win) (VIDOSD_BASE + 0x18 + (win) * 16) -/* size control register for hardware window 1 ~ 4. */ +/* + * size control register for hardware windows 0 and alpha control register + * for hardware windows 1 ~ 4 + */ +#define VIDOSD_C(win) (VIDOSD_BASE + 0x08 + (win) * 16) +/* size control register for hardware windows 1 ~ 2. */ #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) @@ -50,9 +51,9 @@ #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) /* color key control register for hardware window 1 ~ 4. */ -#define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + (x * 8)) +#define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + ((x - 1) * 8)) /* color key value register for hardware window 1 ~ 4. */ -#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + (x * 8)) +#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 @@ -581,7 +582,7 @@ static void fimd_win_commit(struct device *dev, int zpos) if (win != 3 && win != 4) { u32 offset = VIDOSD_D(win); if (win == 0) - offset = VIDOSD_C_SIZE_W0; + offset = VIDOSD_C(win); val = win_data->ovl_width * win_data->ovl_height; writel(val, ctx->regs + offset); -- cgit v1.2.3 From e2779e1698c7dbf36a02a9922d216b4db0e212b8 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghiu Date: Mon, 11 Mar 2013 21:25:22 +0200 Subject: drm/exynos: Replaced kzalloc & memcpy with kmemdup Replaced calls to kzalloc followed by memcpy with call to kmemdup. Patch found using coccinelle. Signed-off-by: Alexandru Gheorghiu Acked-by: Seung-Woo Kim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 13ccbd4bcfaa..9504b0cd825a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -117,13 +117,12 @@ static struct edid *vidi_get_edid(struct device *dev, } edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; - edid = kzalloc(edid_len, GFP_KERNEL); + edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); if (!edid) { DRM_DEBUG_KMS("failed to allocate edid\n"); return ERR_PTR(-ENOMEM); } - memcpy(edid, ctx->raw_edid, edid_len); return edid; } @@ -563,12 +562,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, return -EINVAL; } edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; - ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); + ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL); if (!ctx->raw_edid) { DRM_DEBUG_KMS("failed to allocate raw_edid.\n"); return -ENOMEM; } - memcpy(ctx->raw_edid, raw_edid, edid_len); } else { /* * with connection = 0, free raw_edid -- cgit v1.2.3 From 067ed3311f7961bef67551fa5115dbadf9a035f4 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 11 Mar 2013 19:48:05 +0900 Subject: drm/exynos: Fix error routine to getting dma addr. This patch fixes error routine when g2d_userptr_get_dma_add is failed. When sg_alloc_table_from_pages() is failed, it doesn't call sg_free_table() anymore. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 3b0da0378acf..28b71125189b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -450,7 +450,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, DMA_BIDIRECTIONAL); if (ret < 0) { DRM_ERROR("failed to map sgt with dma region.\n"); - goto err_free_sgt; + goto err_sg_free_table; } g2d_userptr->dma_addr = sgt->sgl[0].dma_address; @@ -467,8 +467,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, return &g2d_userptr->dma_addr; -err_free_sgt: +err_sg_free_table: sg_free_table(sgt); + +err_free_sgt: kfree(sgt); sgt = NULL; -- cgit v1.2.3 From 5efc1d1b53ba60a89ce8269880ed02eddecd1add Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 11 Mar 2013 19:56:17 +0900 Subject: drm/exynos: clear node object type at gem unmap This patch clears node object type in G2D unmap cmdlist. The obj_type of cmdlist node has to be cleared in g2d_unmap_cmdlist_gem() so that the node can be reused in g2d_map_cmdlist_gem(). Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 28b71125189b..095520fdf5eb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -576,6 +576,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, false); node->handles[i] = 0; + node->obj_type[i] = 0; } node->map_nr = 0; -- cgit v1.2.3 From 7ad018140cc9c0e3388243e524f8410e5f174658 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 13 Mar 2013 16:44:37 +0900 Subject: drm/exynos: Fix G2D core malfunctioning issue This patch fixes G2D core malfunctioning issue once g2d dma is started. Without 'DMA_HOLD_CMD_REG' register setting, there is only one interrupt after the execution to all command lists have been completed. And that induces watchdog. So this patch sets 'LIST_HOLD' command to the register so that command execution interrupt can be occured whenever each command list execution is finished. Changelog v2: - Consider for interrupt setup to each command list and all command lists And correct typo. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 095520fdf5eb..1ff11443f552 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -82,7 +82,7 @@ #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17 /* G2D_DMA_HOLD_CMD */ -#define G2D_USET_HOLD (1 << 2) +#define G2D_USER_HOLD (1 << 2) #define G2D_LIST_HOLD (1 << 1) #define G2D_BITBLT_HOLD (1 << 0) @@ -592,10 +592,6 @@ static void g2d_dma_start(struct g2d_data *g2d, pm_runtime_get_sync(g2d->dev); clk_enable(g2d->gate_clk); - /* interrupt enable */ - writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF, - g2d->regs + G2D_INTEN); - writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); } @@ -863,9 +859,23 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR; cmdlist->data[cmdlist->last++] = 0; + /* + * 'LIST_HOLD' command should be set to the DMA_HOLD_CMD_REG + * and GCF bit should be set to INTEN register if user wants + * G2D interrupt event once current command list execution is + * finished. + * Otherwise only ACF bit should be set to INTEN register so + * that one interrupt is occured after all command lists + * have been completed. + */ if (node->event) { + cmdlist->data[cmdlist->last++] = G2D_INTEN; + cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF | G2D_INTEN_GCF; cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD; cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; + } else { + cmdlist->data[cmdlist->last++] = G2D_INTEN; + cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF; } /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ -- cgit v1.2.3 From f3d2fc4a7315d8dd39e6fb37122a3aa08fea6e62 Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 13 Mar 2013 16:55:48 +0900 Subject: drm/exynos: Clean up some G2D codes for readability This patch just cleans up G2D codes for readability. For this, it changes the member of g2d_cmdlist_node, obj_type into buf_type. Changelog v2: - Revert irrelevant codes. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 1ff11443f552..7c1aac3871da 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -131,13 +131,12 @@ struct g2d_cmdlist_userptr { bool in_pool; bool out_of_list; }; - struct g2d_cmdlist_node { struct list_head list; struct g2d_cmdlist *cmdlist; unsigned int map_nr; unsigned long handles[MAX_BUF_ADDR_NR]; - unsigned int obj_type[MAX_BUF_ADDR_NR]; + unsigned int buf_type[MAX_BUF_ADDR_NR]; dma_addr_t dma_addr; struct drm_exynos_pending_g2d_event *event; @@ -524,7 +523,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, offset = cmdlist->last - (i * 2 + 1); handle = cmdlist->data[offset]; - if (node->obj_type[i] == BUF_TYPE_GEM) { + if (node->buf_type[i] == BUF_TYPE_GEM) { addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, file); if (IS_ERR(addr)) { @@ -568,7 +567,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, for (i = 0; i < node->map_nr; i++) { unsigned long handle = node->handles[i]; - if (node->obj_type[i] == BUF_TYPE_GEM) + if (node->buf_type[i] == BUF_TYPE_GEM) exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, filp); else @@ -576,7 +575,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, false); node->handles[i] = 0; - node->obj_type[i] = 0; + node->buf_type[i] = 0; } node->map_nr = 0; @@ -642,7 +641,6 @@ static void g2d_runqueue_worker(struct work_struct *work) struct g2d_data *g2d = container_of(work, struct g2d_data, runqueue_work); - mutex_lock(&g2d->runqueue_mutex); clk_disable(g2d->gate_clk); pm_runtime_put_sync(g2d->dev); @@ -730,7 +728,7 @@ static int g2d_check_reg_offset(struct device *dev, reg_offset = (cmdlist->data[index] & ~0x7fffffff) >> 31; if (reg_offset) { - node->obj_type[i] = BUF_TYPE_USERPTR; + node->buf_type[i] = BUF_TYPE_USERPTR; cmdlist->data[index] &= ~G2D_BUF_USERPTR; } } @@ -752,8 +750,8 @@ static int g2d_check_reg_offset(struct device *dev, if (!for_addr) goto err; - if (node->obj_type[i] != BUF_TYPE_USERPTR) - node->obj_type[i] = BUF_TYPE_GEM; + if (node->buf_type[i] != BUF_TYPE_USERPTR) + node->buf_type[i] = BUF_TYPE_GEM; break; default: if (for_addr) -- cgit v1.2.3 From 9963cb6ef9e6f925617b3c74f0700bf5fbee9a1d Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Wed, 13 Mar 2013 17:10:08 +0900 Subject: drm/exynos: Deal with g2d buffer info more efficiently This patch adds g2d_buf_info structure and buffer relevant variables moves into the g2d_buf_info to manage g2d buffer information more efficiently. Changelog v2: - Fix merge conflict. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 160 ++++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 7c1aac3871da..1a022dc4188e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -96,8 +96,6 @@ #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) -#define MAX_BUF_ADDR_NR 6 - /* maximum buffer pool size of userptr is 64MB as default */ #define MAX_POOL (64 * 1024 * 1024) @@ -106,6 +104,17 @@ enum { BUF_TYPE_USERPTR, }; +enum g2d_reg_type { + REG_TYPE_NONE = -1, + REG_TYPE_SRC, + REG_TYPE_SRC_PLANE2, + REG_TYPE_DST, + REG_TYPE_DST_PLANE2, + REG_TYPE_PAT, + REG_TYPE_MSK, + MAX_REG_TYPE_NR +}; + /* cmdlist data structure */ struct g2d_cmdlist { u32 head; @@ -113,6 +122,22 @@ struct g2d_cmdlist { u32 last; /* last data offset */ }; +/* + * A structure of buffer information + * + * @map_nr: manages the number of mapped buffers + * @reg_types: stores regitster type in the order of requested command + * @handles: stores buffer handle in its reg_type position + * @types: stores buffer type in its reg_type position + * + */ +struct g2d_buf_info { + unsigned int map_nr; + enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; + unsigned long handles[MAX_REG_TYPE_NR]; + unsigned int types[MAX_REG_TYPE_NR]; +}; + struct drm_exynos_pending_g2d_event { struct drm_pending_event base; struct drm_exynos_g2d_event event; @@ -134,10 +159,8 @@ struct g2d_cmdlist_userptr { struct g2d_cmdlist_node { struct list_head list; struct g2d_cmdlist *cmdlist; - unsigned int map_nr; - unsigned long handles[MAX_BUF_ADDR_NR]; - unsigned int buf_type[MAX_BUF_ADDR_NR]; dma_addr_t dma_addr; + struct g2d_buf_info buf_info; struct drm_exynos_pending_g2d_event *event; }; @@ -187,6 +210,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) struct exynos_drm_subdrv *subdrv = &g2d->subdrv; int nr; int ret; + struct g2d_buf_info *buf_info; init_dma_attrs(&g2d->cmdlist_dma_attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); @@ -208,11 +232,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) } for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { + unsigned int i; + node[nr].cmdlist = g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; node[nr].dma_addr = g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; + buf_info = &node[nr].buf_info; + for (i = 0; i < MAX_REG_TYPE_NR; i++) + buf_info->reg_types[i] = REG_TYPE_NONE; + list_add_tail(&node[nr].list, &g2d->free_cmdlist); } @@ -507,36 +537,80 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev, g2d->current_pool = 0; } +static enum g2d_reg_type g2d_get_reg_type(int reg_offset) +{ + enum g2d_reg_type reg_type; + + switch (reg_offset) { + case G2D_SRC_BASE_ADDR: + reg_type = REG_TYPE_SRC; + break; + case G2D_SRC_PLANE2_BASE_ADDR: + reg_type = REG_TYPE_SRC_PLANE2; + break; + case G2D_DST_BASE_ADDR: + reg_type = REG_TYPE_DST; + break; + case G2D_DST_PLANE2_BASE_ADDR: + reg_type = REG_TYPE_DST_PLANE2; + break; + case G2D_PAT_BASE_ADDR: + reg_type = REG_TYPE_PAT; + break; + case G2D_MSK_BASE_ADDR: + reg_type = REG_TYPE_MSK; + break; + default: + reg_type = REG_TYPE_NONE; + DRM_ERROR("Unknown register offset![%d]\n", reg_offset); + break; + }; + + return reg_type; +} + static int g2d_map_cmdlist_gem(struct g2d_data *g2d, struct g2d_cmdlist_node *node, struct drm_device *drm_dev, struct drm_file *file) { struct g2d_cmdlist *cmdlist = node->cmdlist; + struct g2d_buf_info *buf_info = &node->buf_info; int offset; + int ret; int i; - for (i = 0; i < node->map_nr; i++) { + for (i = 0; i < buf_info->map_nr; i++) { + enum g2d_reg_type reg_type; + int reg_pos; unsigned long handle; dma_addr_t *addr; - offset = cmdlist->last - (i * 2 + 1); - handle = cmdlist->data[offset]; + reg_pos = cmdlist->last - 2 * (i + 1); + + offset = cmdlist->data[reg_pos]; + handle = cmdlist->data[reg_pos + 1]; + + reg_type = g2d_get_reg_type(offset); + if (reg_type == REG_TYPE_NONE) { + ret = -EFAULT; + goto err; + } - if (node->buf_type[i] == BUF_TYPE_GEM) { + if (buf_info->types[reg_type] == BUF_TYPE_GEM) { addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, file); if (IS_ERR(addr)) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; } } else { struct drm_exynos_g2d_userptr g2d_userptr; if (copy_from_user(&g2d_userptr, (void __user *)handle, sizeof(struct drm_exynos_g2d_userptr))) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; } addr = g2d_userptr_get_dma_addr(drm_dev, @@ -545,16 +619,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, file, &handle); if (IS_ERR(addr)) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; } } - cmdlist->data[offset] = *addr; - node->handles[i] = handle; + cmdlist->data[reg_pos + 1] = *addr; + buf_info->reg_types[i] = reg_type; + buf_info->handles[reg_type] = handle; } return 0; + +err: + buf_info->map_nr = i; + return ret; } static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, @@ -562,23 +641,30 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, struct drm_file *filp) { struct exynos_drm_subdrv *subdrv = &g2d->subdrv; + struct g2d_buf_info *buf_info = &node->buf_info; int i; - for (i = 0; i < node->map_nr; i++) { - unsigned long handle = node->handles[i]; + for (i = 0; i < buf_info->map_nr; i++) { + enum g2d_reg_type reg_type; + unsigned long handle; + + reg_type = buf_info->reg_types[i]; - if (node->buf_type[i] == BUF_TYPE_GEM) + handle = buf_info->handles[reg_type]; + + if (buf_info->types[reg_type] == BUF_TYPE_GEM) exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, filp); else g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, false); - node->handles[i] = 0; - node->buf_type[i] = 0; + buf_info->reg_types[i] = REG_TYPE_NONE; + buf_info->handles[reg_type] = 0; + buf_info->types[reg_type] = 0; } - node->map_nr = 0; + buf_info->map_nr = 0; } static void g2d_dma_start(struct g2d_data *g2d, @@ -721,20 +807,12 @@ static int g2d_check_reg_offset(struct device *dev, int i; for (i = 0; i < nr; i++) { - index = cmdlist->last - 2 * (i + 1); + struct g2d_buf_info *buf_info = &node->buf_info; + enum g2d_reg_type reg_type; - if (for_addr) { - /* check userptr buffer type. */ - reg_offset = (cmdlist->data[index] & - ~0x7fffffff) >> 31; - if (reg_offset) { - node->buf_type[i] = BUF_TYPE_USERPTR; - cmdlist->data[index] &= ~G2D_BUF_USERPTR; - } - } + index = cmdlist->last - 2 * (i + 1); reg_offset = cmdlist->data[index] & ~0xfffff000; - if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) goto err; if (reg_offset % 4) @@ -750,8 +828,16 @@ static int g2d_check_reg_offset(struct device *dev, if (!for_addr) goto err; - if (node->buf_type[i] != BUF_TYPE_USERPTR) - node->buf_type[i] = BUF_TYPE_GEM; + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + /* check userptr buffer type. */ + if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { + buf_info->types[reg_type] = BUF_TYPE_USERPTR; + cmdlist->data[index] &= ~G2D_BUF_USERPTR; + } else + buf_info->types[reg_type] = BUF_TYPE_GEM; break; default: if (for_addr) @@ -898,7 +984,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, if (ret < 0) goto err_free_event; - node->map_nr = req->cmd_buf_nr; + node->buf_info.map_nr = req->cmd_buf_nr; if (req->cmd_buf_nr) { struct drm_exynos_g2d_cmd *cmd_buf; -- cgit v1.2.3 From a4f19aaab3e69f9d15cc995e3378d27c8ef4f780 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 11 Mar 2013 21:15:59 +0900 Subject: drm/exynos: Add a new function to get gem buffer size This patch adds a new function to get gem buffer size. And this funtion could be used for g2d driver or others can get gem buffer size to check if the buffer is valid or not. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 21 +++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_gem.h | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 67e17ce112b6..0e6fe000578c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -164,6 +164,27 @@ out: exynos_gem_obj = NULL; } +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, + unsigned int gem_handle, + struct drm_file *file_priv) +{ + struct exynos_drm_gem_obj *exynos_gem_obj; + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, file_priv, gem_handle); + if (!obj) { + DRM_ERROR("failed to lookup gem object.\n"); + return 0; + } + + exynos_gem_obj = to_exynos_gem_obj(obj); + + drm_gem_object_unreference_unlocked(obj); + + return exynos_gem_obj->buffer->size; +} + + struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, unsigned long size) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 35ebac47dc2b..468766bee450 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -130,6 +130,11 @@ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* get buffer size to gem handle. */ +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, + unsigned int gem_handle, + struct drm_file *file_priv); + /* initialize gem object. */ int exynos_drm_gem_init_object(struct drm_gem_object *obj); -- cgit v1.2.3 From 2dec17c70e7567f226331c26d8daa0c16d3e7e6d Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Mon, 11 Mar 2013 21:17:52 +0900 Subject: drm/exynos: Check g2d cmd list for g2d restrictions This patch checks command list from user for g2d restrictions. For now, g2d driver wasn't considered for G2D hardware restrictions properly. The below is the restrictions to G2D hardware and this patch considers them. - width or height value in the command list has to be in valid range (1 to 8000 pixels) - The requested area should be less than buffer size. - right has to be bigger than left. - bottom has to be bigger than top. Changelog v2: - Fix merge conflict. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 183 ++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 1a022dc4188e..47a493c8a71f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -48,8 +48,14 @@ /* registers for base address */ #define G2D_SRC_BASE_ADDR 0x0304 +#define G2D_SRC_COLOR_MODE 0x030C +#define G2D_SRC_LEFT_TOP 0x0310 +#define G2D_SRC_RIGHT_BOTTOM 0x0314 #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 #define G2D_DST_BASE_ADDR 0x0404 +#define G2D_DST_COLOR_MODE 0x040C +#define G2D_DST_LEFT_TOP 0x0410 +#define G2D_DST_RIGHT_BOTTOM 0x0414 #define G2D_DST_PLANE2_BASE_ADDR 0x0418 #define G2D_PAT_BASE_ADDR 0x0500 #define G2D_MSK_BASE_ADDR 0x0520 @@ -91,6 +97,22 @@ #define G2D_START_NHOLT (1 << 1) #define G2D_START_BITBLT (1 << 0) +/* buffer color format */ +#define G2D_FMT_XRGB8888 0 +#define G2D_FMT_ARGB8888 1 +#define G2D_FMT_RGB565 2 +#define G2D_FMT_XRGB1555 3 +#define G2D_FMT_ARGB1555 4 +#define G2D_FMT_XRGB4444 5 +#define G2D_FMT_ARGB4444 6 +#define G2D_FMT_PACKED_RGB888 7 +#define G2D_FMT_A8 11 +#define G2D_FMT_L8 12 + +/* buffer valid length */ +#define G2D_LEN_MIN 1 +#define G2D_LEN_MAX 8000 + #define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) #define G2D_CMDLIST_NUM 64 #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) @@ -122,6 +144,24 @@ struct g2d_cmdlist { u32 last; /* last data offset */ }; +/* + * A structure of buffer description + * + * @format: color format + * @left_x: the x coordinates of left top corner + * @top_y: the y coordinates of left top corner + * @right_x: the x coordinates of right bottom corner + * @bottom_y: the y coordinates of right bottom corner + * + */ +struct g2d_buf_desc { + unsigned int format; + unsigned int left_x; + unsigned int top_y; + unsigned int right_x; + unsigned int bottom_y; +}; + /* * A structure of buffer information * @@ -129,6 +169,7 @@ struct g2d_cmdlist { * @reg_types: stores regitster type in the order of requested command * @handles: stores buffer handle in its reg_type position * @types: stores buffer type in its reg_type position + * @descs: stores buffer description in its reg_type position * */ struct g2d_buf_info { @@ -136,6 +177,7 @@ struct g2d_buf_info { enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; unsigned long handles[MAX_REG_TYPE_NR]; unsigned int types[MAX_REG_TYPE_NR]; + struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; }; struct drm_exynos_pending_g2d_event { @@ -543,12 +585,18 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) switch (reg_offset) { case G2D_SRC_BASE_ADDR: + case G2D_SRC_COLOR_MODE: + case G2D_SRC_LEFT_TOP: + case G2D_SRC_RIGHT_BOTTOM: reg_type = REG_TYPE_SRC; break; case G2D_SRC_PLANE2_BASE_ADDR: reg_type = REG_TYPE_SRC_PLANE2; break; case G2D_DST_BASE_ADDR: + case G2D_DST_COLOR_MODE: + case G2D_DST_LEFT_TOP: + case G2D_DST_RIGHT_BOTTOM: reg_type = REG_TYPE_DST; break; case G2D_DST_PLANE2_BASE_ADDR: @@ -569,6 +617,69 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) return reg_type; } +static unsigned long g2d_get_buf_bpp(unsigned int format) +{ + unsigned long bpp; + + switch (format) { + case G2D_FMT_XRGB8888: + case G2D_FMT_ARGB8888: + bpp = 4; + break; + case G2D_FMT_RGB565: + case G2D_FMT_XRGB1555: + case G2D_FMT_ARGB1555: + case G2D_FMT_XRGB4444: + case G2D_FMT_ARGB4444: + bpp = 2; + break; + case G2D_FMT_PACKED_RGB888: + bpp = 3; + break; + default: + bpp = 1; + break; + } + + return bpp; +} + +static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, + enum g2d_reg_type reg_type, + unsigned long size) +{ + unsigned int width, height; + unsigned long area; + + /* + * check source and destination buffers only. + * so the others are always valid. + */ + if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST) + return true; + + width = buf_desc->right_x - buf_desc->left_x; + if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { + DRM_ERROR("width[%u] is out of range!\n", width); + return false; + } + + height = buf_desc->bottom_y - buf_desc->top_y; + if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { + DRM_ERROR("height[%u] is out of range!\n", height); + return false; + } + + area = (unsigned long)width * (unsigned long)height * + g2d_get_buf_bpp(buf_desc->format); + if (area > size) { + DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); + return false; + } + + return true; +} + static int g2d_map_cmdlist_gem(struct g2d_data *g2d, struct g2d_cmdlist_node *node, struct drm_device *drm_dev, @@ -581,6 +692,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, int i; for (i = 0; i < buf_info->map_nr; i++) { + struct g2d_buf_desc *buf_desc; enum g2d_reg_type reg_type; int reg_pos; unsigned long handle; @@ -597,7 +709,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, goto err; } + buf_desc = &buf_info->descs[reg_type]; + if (buf_info->types[reg_type] == BUF_TYPE_GEM) { + unsigned long size; + + size = exynos_drm_gem_get_size(drm_dev, handle, file); + if (!size) { + ret = -EFAULT; + goto err; + } + + if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, + size)) { + ret = -EFAULT; + goto err; + } + addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, file); if (IS_ERR(addr)) { @@ -613,6 +741,12 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, goto err; } + if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, + g2d_userptr.size)) { + ret = -EFAULT; + goto err; + } + addr = g2d_userptr_get_dma_addr(drm_dev, g2d_userptr.userptr, g2d_userptr.size, @@ -645,11 +779,13 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, int i; for (i = 0; i < buf_info->map_nr; i++) { + struct g2d_buf_desc *buf_desc; enum g2d_reg_type reg_type; unsigned long handle; reg_type = buf_info->reg_types[i]; + buf_desc = &buf_info->descs[reg_type]; handle = buf_info->handles[reg_type]; if (buf_info->types[reg_type] == BUF_TYPE_GEM) @@ -662,6 +798,7 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, buf_info->reg_types[i] = REG_TYPE_NONE; buf_info->handles[reg_type] = 0; buf_info->types[reg_type] = 0; + memset(buf_desc, 0x00, sizeof(*buf_desc)); } buf_info->map_nr = 0; @@ -808,7 +945,9 @@ static int g2d_check_reg_offset(struct device *dev, for (i = 0; i < nr; i++) { struct g2d_buf_info *buf_info = &node->buf_info; + struct g2d_buf_desc *buf_desc; enum g2d_reg_type reg_type; + unsigned long value; index = cmdlist->last - 2 * (i + 1); @@ -839,6 +978,50 @@ static int g2d_check_reg_offset(struct device *dev, } else buf_info->types[reg_type] = BUF_TYPE_GEM; break; + case G2D_SRC_COLOR_MODE: + case G2D_DST_COLOR_MODE: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->format = value & 0xf; + break; + case G2D_SRC_LEFT_TOP: + case G2D_DST_LEFT_TOP: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->left_x = value & 0x1fff; + buf_desc->top_y = (value & 0x1fff0000) >> 16; + break; + case G2D_SRC_RIGHT_BOTTOM: + case G2D_DST_RIGHT_BOTTOM: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->right_x = value & 0x1fff; + buf_desc->bottom_y = (value & 0x1fff0000) >> 16; + break; default: if (for_addr) goto err; -- cgit v1.2.3 From bec964ed3b2549086e1fdfbf7f1ce8c22f89baa4 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 20 Mar 2013 10:50:50 +0100 Subject: NFC: llcp: Detach socket from process context only when releasing the socket Calling sock_orphan when e.g. the NFC adapter is removed can lead to kernel crashes when e.g. a connection less client is sleeping on the Rx workqueue, waiting for data to show up. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 6 ------ net/nfc/llcp/sock.c | 2 -- 2 files changed, 8 deletions(-) diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index b530afadd76c..336813ff8cd5 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -107,8 +107,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, accept_sk->sk_state_change(sk); bh_unlock_sock(accept_sk); - - sock_orphan(accept_sk); } if (listen == true) { @@ -134,8 +132,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, bh_unlock_sock(sk); - sock_orphan(sk); - sk_del_node_init(sk); } @@ -164,8 +160,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, bh_unlock_sock(sk); - sock_orphan(sk); - sk_del_node_init(sk); } diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 5c7cdf3f2a83..e488e440186a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -464,8 +464,6 @@ static int llcp_sock_release(struct socket *sock) nfc_llcp_accept_unlink(accept_sk); release_sock(accept_sk); - - sock_orphan(accept_sk); } } -- cgit v1.2.3 From 0017c0b57500606aab894cdb02fdf3380ddd60ee Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 11 Mar 2013 10:32:16 +0100 Subject: xfrm: Fix replay notification for esn. We may miscalculate the sequence number difference from the last time we send a notification if a sequence number wrap occured in the meantime. We fix this by adding a separate replay notify function for esn. Here we take the high bits of the sequence number into account to calculate the difference. Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_replay.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 35754cc8a9e5..a3906737f49e 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -334,6 +334,72 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) x->xflags &= ~XFRM_TIME_DEFER; } +static void xfrm_replay_notify_esn(struct xfrm_state *x, int event) +{ + u32 seq_diff, oseq_diff; + struct km_event c; + struct xfrm_replay_state_esn *replay_esn = x->replay_esn; + struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn; + + /* we send notify messages in case + * 1. we updated on of the sequence numbers, and the seqno difference + * is at least x->replay_maxdiff, in this case we also update the + * timeout of our timer function + * 2. if x->replay_maxage has elapsed since last update, + * and there were changes + * + * The state structure must be locked! + */ + + switch (event) { + case XFRM_REPLAY_UPDATE: + if (!x->replay_maxdiff) + break; + + if (replay_esn->seq_hi == preplay_esn->seq_hi) + seq_diff = replay_esn->seq - preplay_esn->seq; + else + seq_diff = UINT_MAX - preplay_esn->seq + + replay_esn->seq; + + if (replay_esn->oseq_hi == preplay_esn->oseq_hi) + oseq_diff = replay_esn->oseq - preplay_esn->oseq; + else + oseq_diff = UINT_MAX - preplay_esn->oseq + + replay_esn->oseq; + + if (seq_diff < x->replay_maxdiff && + oseq_diff < x->replay_maxdiff) { + + if (x->xflags & XFRM_TIME_DEFER) + event = XFRM_REPLAY_TIMEOUT; + else + return; + } + + break; + + case XFRM_REPLAY_TIMEOUT: + if (memcmp(x->replay_esn, x->preplay_esn, + xfrm_replay_state_esn_len(replay_esn)) == 0) { + x->xflags |= XFRM_TIME_DEFER; + return; + } + + break; + } + + memcpy(x->preplay_esn, x->replay_esn, + xfrm_replay_state_esn_len(replay_esn)); + c.event = XFRM_MSG_NEWAE; + c.data.aevent = event; + km_state_notify(x, &c); + + if (x->replay_maxage && + !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) + x->xflags &= ~XFRM_TIME_DEFER; +} + static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb) { int err = 0; @@ -510,7 +576,7 @@ static struct xfrm_replay xfrm_replay_esn = { .advance = xfrm_replay_advance_esn, .check = xfrm_replay_check_esn, .recheck = xfrm_replay_recheck_esn, - .notify = xfrm_replay_notify_bmp, + .notify = xfrm_replay_notify_esn, .overflow = xfrm_replay_overflow_esn, }; -- cgit v1.2.3 From cc904c7188c29847817f35e6966fec3014c7479b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 14 Mar 2013 08:35:06 +0200 Subject: iwlwifi: fix length check in multi-TB HCMD As reported by Ben Hutchings, there was a harmless issue in the checks being done on the lengths of the TBs while building the TFD for a multi-TB host command. Cc: stable@vger@kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8595c16f74de..cb5c6792e3a8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1264,7 +1264,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { int copy = 0; - if (!cmd->len) + if (!cmd->len[i]) continue; /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ -- cgit v1.2.3 From 4620020b5d7ca34d1c03fa98b0ca457320cb7d71 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 13 Mar 2013 16:38:32 +0200 Subject: iwlwifi: set rfkill in internal state of the transport We didn't update the internal of the PCIe transport when we read the RFkill state directly. Fix that. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/pcie/trans.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 17bedc50e753..12c4f31ca8fb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* If platform's RF_KILL switch is NOT set to KILL */ hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) + set_bit(STATUS_RFKILL, &trans_pcie->status); + else + clear_bit(STATUS_RFKILL, &trans_pcie->status); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); if (hw_rfkill && !run_in_rfkill) return -ERFKILL; @@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; int err; @@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) iwl_enable_rfkill_int(trans); hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) + set_bit(STATUS_RFKILL, &trans_pcie->status); + else + clear_bit(STATUS_RFKILL, &trans_pcie->status); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); return 0; @@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, * op_mode. */ hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) + set_bit(STATUS_RFKILL, &trans_pcie->status); + else + clear_bit(STATUS_RFKILL, &trans_pcie->status); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); } } -- cgit v1.2.3 From 2d5d50ee596361566f7f84300117cba7d7672bc5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 31 Jan 2013 15:03:55 +0200 Subject: iwlwifi: dvm: don't send HCMD in restart flow There is a race between the restart flow and the workers. The workers are cancelled after the fw is already killed and might send HCMD when there is fw to handle them. Simply check that there is a fw to which the HCMD can be sent before actually sending it. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/lib.c | 9 +++++++++ drivers/net/wireless/iwlwifi/dvm/ucode.c | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 86ea5f4c3939..44ca0e57f9f7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -1261,6 +1261,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + /* + * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag + * in iwl_down but cancel the workers only later. + */ + if (!priv->ucode_loaded) { + IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id); + return -EIO; + } + /* * Synchronous commands from this op-mode must hold * the mutex, this ensures we don't try to send two diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 736fe9bb140e..1a4ac9236a44 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, return -EIO; } + priv->ucode_loaded = true; + if (ucode_type != IWL_UCODE_WOWLAN) { /* delay a bit to give rfkill time to run */ msleep(5); @@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, return ret; } - priv->ucode_loaded = true; - return 0; } -- cgit v1.2.3 From 367f3fcd9296977bc4689546f55c5f4a9c680e8d Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 20 Mar 2013 16:53:14 +0530 Subject: ARC: Fix the typo in event identifier flags used by ptrace orig_r8_IS_EXCPN and orig_r8_IS_BRKPT were same values due to a copy/paste error. Although it looks bad and is wrong, it really doesn't affect gdb working. orig_r8_IS_BRKPT is the one relevant to debugging (breakpoints), since it is used to provide EFA vs. ERET to a ptrace "stop_pc" request. So when gdb has inserted a breakpoint, orig_r8_IS_BRKPT is already set, and anything else (i.e. orig_r8_IS_EXCPN) becoming same as it, really doesn't hurt gdb. The corollary case, could be nasty but nobody uses the ptrace "stop_pc" request in that case Signed-off-by: Vineet Gupta --- arch/arc/include/asm/entry.h | 2 +- arch/arc/include/asm/ptrace.h | 2 +- arch/arc/kernel/entry.S | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h index 23daa326fc9b..eb2ae53187d9 100644 --- a/arch/arc/include/asm/entry.h +++ b/arch/arc/include/asm/entry.h @@ -415,7 +415,7 @@ *-------------------------------------------------------------*/ .macro SAVE_ALL_EXCEPTION marker - st \marker, [sp, 8] + st \marker, [sp, 8] /* orig_r8 */ st r0, [sp, 4] /* orig_r0, needed only for sys calls */ /* Restore r9 used to code the early prologue */ diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 8ae783d20a81..6179de7e07c2 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -123,7 +123,7 @@ static inline long regs_return_value(struct pt_regs *regs) #define orig_r8_IS_SCALL 0x0001 #define orig_r8_IS_SCALL_RESTARTED 0x0002 #define orig_r8_IS_BRKPT 0x0004 -#define orig_r8_IS_EXCPN 0x0004 +#define orig_r8_IS_EXCPN 0x0008 #define orig_r8_IS_IRQ1 0x0010 #define orig_r8_IS_IRQ2 0x0020 diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index b9d875a441cc..91eeab81f52d 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -452,7 +452,7 @@ tracesys: ; using ERET won't work since next-PC has already committed lr r12, [efa] GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11 - st r12, [r11, THREAD_FAULT_ADDR] + st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address ; PRE Sys Call Ptrace hook mov r0, sp ; pt_regs needed -- cgit v1.2.3 From b3155155440190de78fb501953136a6c5b82e327 Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Wed, 20 Mar 2013 16:00:16 +0100 Subject: NFC: llcp: Remove possible double call to kfree_skb kfree_skb was called twice when the socket receive queue is full Signed-off-by: Thierry Escande Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 336813ff8cd5..ee25f25f0cd6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -821,7 +821,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local, skb_get(skb); } else { pr_err("Receive queue is full\n"); - kfree_skb(skb); } nfc_llcp_sock_put(llcp_sock); @@ -1022,7 +1021,6 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, skb_get(skb); } else { pr_err("Receive queue is full\n"); - kfree_skb(skb); } } -- cgit v1.2.3 From f1e79e208076ffe7bad97158275f1c572c04f5c7 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 19 Mar 2013 01:47:27 +0000 Subject: genetlink: trigger BUG_ON if a group name is too long Trigger BUG_ON if a group name is longer than GENL_NAMSIZ. Signed-off-by: Masatake YAMATO Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f2aabb6f4105..5a55be3f17a5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -142,6 +142,7 @@ int genl_register_mc_group(struct genl_family *family, int err = 0; BUG_ON(grp->name[0] == '\0'); + BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL); genl_lock(); -- cgit v1.2.3 From 44046a593eb770dbecdabf1c82bcd252f2a8337b Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:12 +0000 Subject: udp: add encap_destroy callback Users of udp encapsulation currently have an encap_rcv callback which they can use to hook into the udp receive path. In situations where a encapsulation user allocates resources associated with a udp encap socket, it may be convenient to be able to also hook the proto .destroy operation. For example, if an encap user holds a reference to the udp socket, the destroy hook might be used to relinquish this reference. This patch adds a socket destroy hook into udp, which is set and enabled in the same way as the existing encap_rcv hook. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- include/linux/udp.h | 1 + net/ipv4/udp.c | 7 +++++++ net/ipv6/udp.c | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/include/linux/udp.h b/include/linux/udp.h index 9d81de123c90..42278bbf7a88 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -68,6 +68,7 @@ struct udp_sock { * For encapsulation sockets. */ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); + void (*encap_destroy)(struct sock *sk); }; static inline struct udp_sock *udp_sk(const struct sock *sk) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 265c42cf963c..0a073a263720 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1762,9 +1762,16 @@ int udp_rcv(struct sk_buff *skb) void udp_destroy_sock(struct sock *sk) { + struct udp_sock *up = udp_sk(sk); bool slow = lock_sock_fast(sk); udp_flush_pending_frames(sk); unlock_sock_fast(sk, slow); + if (static_key_false(&udp_encap_needed) && up->encap_type) { + void (*encap_destroy)(struct sock *sk); + encap_destroy = ACCESS_ONCE(up->encap_destroy); + if (encap_destroy) + encap_destroy(sk); + } } /* diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 599e1ba6d1ce..d8e5e852fc7a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1285,10 +1285,18 @@ do_confirm: void udpv6_destroy_sock(struct sock *sk) { + struct udp_sock *up = udp_sk(sk); lock_sock(sk); udp_v6_flush_pending_frames(sk); release_sock(sk); + if (static_key_false(&udpv6_encap_needed) && up->encap_type) { + void (*encap_destroy)(struct sock *sk); + encap_destroy = ACCESS_ONCE(up->encap_destroy); + if (encap_destroy) + encap_destroy(sk); + } + inet6_destroy_sock(sk); } -- cgit v1.2.3 From 9980d001cec86c3c75f3a6008ddb73c397ea3b3e Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:13 +0000 Subject: l2tp: add udp encap socket destroy handler L2TP sessions hold a reference to the tunnel socket to prevent it going away while sessions are still active. However, since tunnel destruction is handled by the sock sk_destruct callback there is a catch-22: a tunnel with sessions cannot be deleted since each session holds a reference to the tunnel socket. If userspace closes a managed tunnel socket, or dies, the tunnel will persist and it will be neccessary to individually delete the sessions using netlink commands. This is ugly. To prevent this occuring, this patch leverages the udp encapsulation socket destroy callback to gain early notification when the tunnel socket is closed. This allows us to safely close the sessions running in the tunnel, dropping the tunnel socket references in the process. The tunnel socket is then destroyed as normal, and the tunnel resources deallocated in sk_destruct. While we're at it, ensure that l2tp_tunnel_closeall correctly drops session references to allow the sessions to be deleted rather than leaking. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index d36875f3427e..ee726a752292 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1282,6 +1282,7 @@ static void l2tp_tunnel_destruct(struct sock *sk) /* No longer an encapsulation socket. See net/ipv4/udp.c */ (udp_sk(sk))->encap_type = 0; (udp_sk(sk))->encap_rcv = NULL; + (udp_sk(sk))->encap_destroy = NULL; break; case L2TP_ENCAPTYPE_IP: break; @@ -1360,6 +1361,8 @@ again: if (session->deref != NULL) (*session->deref)(session); + l2tp_session_dec_refcount(session); + write_lock_bh(&tunnel->hlist_lock); /* Now restart from the beginning of this hash @@ -1373,6 +1376,16 @@ again: write_unlock_bh(&tunnel->hlist_lock); } +/* Tunnel socket destroy hook for UDP encapsulation */ +static void l2tp_udp_encap_destroy(struct sock *sk) +{ + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } +} + /* Really kill the tunnel. * Come here only when all sessions have been cleared from the tunnel. */ @@ -1668,6 +1681,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; + udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy; #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == PF_INET6) udpv6_encap_enable(); -- cgit v1.2.3 From e34f4c7050e5471b6d4fb25380713937fc837514 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:14 +0000 Subject: l2tp: export l2tp_tunnel_closeall l2tp_core internally uses l2tp_tunnel_closeall to close all sessions in a tunnel when a UDP-encapsulation socket is destroyed. We need to do something similar for IP-encapsulation sockets. Export l2tp_tunnel_closeall as a GPL symbol to enable l2tp_ip and l2tp_ip6 to call it from their .destroy handlers. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 4 ++-- net/l2tp/l2tp_core.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index ee726a752292..287e327342d1 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -114,7 +114,6 @@ struct l2tp_net { static void l2tp_session_set_header_len(struct l2tp_session *session, int version); static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); static inline struct l2tp_net *l2tp_pernet(struct net *net) { @@ -1312,7 +1311,7 @@ end: /* When the tunnel is closed, all the attached sessions need to go too. */ -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) +void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) { int hash; struct hlist_node *walk; @@ -1375,6 +1374,7 @@ again: } write_unlock_bh(&tunnel->hlist_lock); } +EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); /* Tunnel socket destroy hook for UDP encapsulation */ static void l2tp_udp_encap_destroy(struct sock *sk) diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 8eb8f1d47f3a..b0861f68a10b 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -240,6 +240,7 @@ extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp); +extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); extern int l2tp_session_delete(struct l2tp_session *session); -- cgit v1.2.3 From 936063175afd895913a5e9db77e1a0ef43ea44ea Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:15 +0000 Subject: l2tp: close sessions in ip socket destroy callback l2tp_core hooks UDP's .destroy handler to gain advance warning of a tunnel socket being closed from userspace. We need to do the same thing for IP-encapsulation sockets. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_ip.c | 6 ++++++ net/l2tp/l2tp_ip6.c | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 7f41b7051269..571db8dd2292 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -228,10 +228,16 @@ static void l2tp_ip_close(struct sock *sk, long timeout) static void l2tp_ip_destroy_sock(struct sock *sk) { struct sk_buff *skb; + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) kfree_skb(skb); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } + sk_refcnt_debug_dec(sk); } diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 41f2f8126ebc..c74f5a91ff6a 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -241,10 +241,17 @@ static void l2tp_ip6_close(struct sock *sk, long timeout) static void l2tp_ip6_destroy_sock(struct sock *sk) { + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + lock_sock(sk); ip6_flush_pending_frames(sk); release_sock(sk); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } + inet6_destroy_sock(sk); } -- cgit v1.2.3 From 2b551c6e7d5bca2c78c216b15ef675653d4f459a Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:16 +0000 Subject: l2tp: close sessions before initiating tunnel delete When a user deletes a tunnel using netlink, all the sessions in the tunnel should also be deleted. Since running sessions will pin the tunnel socket with the references they hold, have the l2tp_tunnel_delete close all sessions in a tunnel before finally closing the tunnel socket. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 287e327342d1..0dd50c079f29 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1737,6 +1737,7 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); */ int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) { + l2tp_tunnel_closeall(tunnel); return (false == queue_work(l2tp_wq, &tunnel->del_work)); } EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); -- cgit v1.2.3 From 8abbbe8ff572fd84d1b98eb9acf30611a97cf72e Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:17 +0000 Subject: l2tp: take a reference for kernel sockets in l2tp_tunnel_sock_lookup When looking up the tunnel socket in struct l2tp_tunnel, hold a reference whether the socket was created by the kernel or by userspace. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 0dd50c079f29..45373fee38c5 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -191,6 +191,7 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) } else { /* Socket is owned by kernelspace */ sk = tunnel->sock; + sock_hold(sk); } out: @@ -209,6 +210,7 @@ void l2tp_tunnel_sock_put(struct sock *sk) } sock_put(sk); } + sock_put(sk); } EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put); -- cgit v1.2.3 From 02d13ed5f94af38c37d1abd53462fe48d78bcc9d Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:18 +0000 Subject: l2tp: don't BUG_ON sk_socket being NULL It is valid for an existing struct sock object to have a NULL sk_socket pointer, so don't BUG_ON in l2tp_tunnel_del_work if that should occur. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 45373fee38c5..e841ef2a68a5 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1412,19 +1412,21 @@ static void l2tp_tunnel_del_work(struct work_struct *work) return; sock = sk->sk_socket; - BUG_ON(!sock); - /* If the tunnel socket was created directly by the kernel, use the - * sk_* API to release the socket now. Otherwise go through the - * inet_* layer to shut the socket down, and let userspace close it. + /* If the tunnel socket was created by userspace, then go through the + * inet layer to shut the socket down, and let userspace close it. + * Otherwise, if we created the socket directly within the kernel, use + * the sk API to release it here. * In either case the tunnel resources are freed in the socket * destructor when the tunnel socket goes away. */ - if (sock->file == NULL) { - kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sk); + if (tunnel->fd >= 0) { + if (sock) + inet_shutdown(sock, 2); } else { - inet_shutdown(sock, 2); + if (sock) + kernel_sock_shutdown(sock, SHUT_RDWR); + sk_release_kernel(sk); } l2tp_tunnel_sock_put(sk); -- cgit v1.2.3 From 48f72f92b31431c40279b0fba6c5588e07e67d95 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:19 +0000 Subject: l2tp: add session reorder queue purge function to core If an l2tp session is deleted, it is necessary to delete skbs in-flight on the session's reorder queue before taking it down. Rather than having each pseudowire implementation reaching into the l2tp_session struct to handle this itself, provide a function in l2tp_core to purge the session queue. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 17 +++++++++++++++++ net/l2tp/l2tp_core.h | 1 + 2 files changed, 18 insertions(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index e841ef2a68a5..69c316dd02dc 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -829,6 +829,23 @@ discard: } EXPORT_SYMBOL(l2tp_recv_common); +/* Drop skbs from the session's reorder_q + */ +int l2tp_session_queue_purge(struct l2tp_session *session) +{ + struct sk_buff *skb = NULL; + BUG_ON(!session); + BUG_ON(session->magic != L2TP_SESSION_MAGIC); + while ((skb = skb_dequeue(&session->reorder_q))) { + atomic_long_inc(&session->stats.rx_errors); + kfree_skb(skb); + if (session->deref) + (*session->deref)(session); + } + return 0; +} +EXPORT_SYMBOL_GPL(l2tp_session_queue_purge); + /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame * here. The skb is not on a list when we get here. * Returns 0 if the packet was a data packet and was successfully passed on. diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index b0861f68a10b..d40713d105fc 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -246,6 +246,7 @@ extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunne extern int l2tp_session_delete(struct l2tp_session *session); extern void l2tp_session_free(struct l2tp_session *session); extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); +extern int l2tp_session_queue_purge(struct l2tp_session *session); extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); -- cgit v1.2.3 From 4c6e2fd35460208596fa099ee0750a4b0438aa5c Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:20 +0000 Subject: l2tp: purge session reorder queue on delete Add calls to l2tp_session_queue_purge as a part of l2tp_tunnel_closeall and l2tp_session_delete. Pseudowire implementations which are deleted only via. l2tp_core l2tp_session_delete calls can dispense with their own code for flushing the reorder queue. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 69c316dd02dc..c00f31b8cc04 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1373,6 +1373,8 @@ again: synchronize_rcu(); } + l2tp_session_queue_purge(session); + if (session->session_close != NULL) (*session->session_close)(session); @@ -1813,6 +1815,8 @@ EXPORT_SYMBOL_GPL(l2tp_session_free); */ int l2tp_session_delete(struct l2tp_session *session) { + l2tp_session_queue_purge(session); + if (session->session_close != NULL) (*session->session_close)(session); -- cgit v1.2.3 From cf2f5c886a209377daefd5d2ba0bcd49c3887813 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:21 +0000 Subject: l2tp: push all ppp pseudowire shutdown through .release handler If userspace deletes a ppp pseudowire using the netlink API, either by directly deleting the session or by deleting the tunnel that contains the session, we need to tear down the corresponding pppox channel. Rather than trying to manage two pppox unbind codepaths, switch the netlink and l2tp_core session_close handlers to close via. the l2tp_ppp socket .release handler. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_ppp.c | 53 ++++++++++------------------------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 6a53371dba1f..7e3e16aefcb5 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -97,6 +97,7 @@ #include #include #include +#include #include #include @@ -447,34 +448,16 @@ static void pppol2tp_session_close(struct l2tp_session *session) { struct pppol2tp_session *ps = l2tp_session_priv(session); struct sock *sk = ps->sock; - struct sk_buff *skb; + struct socket *sock = sk->sk_socket; BUG_ON(session->magic != L2TP_SESSION_MAGIC); - if (session->session_id == 0) - goto out; - - if (sk != NULL) { - lock_sock(sk); - - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { - pppox_unbind_sock(sk); - sk->sk_state = PPPOX_DEAD; - sk->sk_state_change(sk); - } - - /* Purge any queued data */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - while ((skb = skb_dequeue(&session->reorder_q))) { - kfree_skb(skb); - sock_put(sk); - } - release_sock(sk); + if (sock) { + inet_shutdown(sock, 2); + /* Don't let the session go away before our socket does */ + l2tp_session_inc_refcount(session); } - -out: return; } @@ -525,16 +508,12 @@ static int pppol2tp_release(struct socket *sock) session = pppol2tp_sock_to_session(sk); /* Purge any queued data */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); if (session != NULL) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&session->reorder_q))) { - kfree_skb(skb); - sock_put(sk); - } + l2tp_session_queue_purge(session); sock_put(sk); } + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); release_sock(sk); @@ -880,18 +859,6 @@ out: return error; } -/* Called when deleting sessions via the netlink interface. - */ -static int pppol2tp_session_delete(struct l2tp_session *session) -{ - struct pppol2tp_session *ps = l2tp_session_priv(session); - - if (ps->sock == NULL) - l2tp_session_dec_refcount(session); - - return 0; -} - #endif /* CONFIG_L2TP_V3 */ /* getname() support. @@ -1839,7 +1806,7 @@ static const struct pppox_proto pppol2tp_proto = { static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = { .session_create = pppol2tp_session_create, - .session_delete = pppol2tp_session_delete, + .session_delete = l2tp_session_delete, }; #endif /* CONFIG_L2TP_V3 */ -- cgit v1.2.3 From 7b7c0719cd7afee725b920d75ec6a500b76107e6 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:22 +0000 Subject: l2tp: avoid deadlock in l2tp stats update l2tp's u64_stats writers were incorrectly synchronised, making it possible to deadlock a 64bit machine running a 32bit kernel simply by sending the l2tp code netlink commands while passing data through l2tp sessions. Previous discussion on netdev determined that alternative solutions such as spinlock writer synchronisation or per-cpu data would bring unjustified overhead, given that most users interested in high volume traffic will likely be running 64bit kernels on 64bit hardware. As such, this patch replaces l2tp's use of u64_stats with atomic_long_t, thereby avoiding the deadlock. Ref: http://marc.info/?l=linux-netdev&m=134029167910731&w=2 http://marc.info/?l=linux-netdev&m=134079868111131&w=2 Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 75 +++++++++++++------------------------------------ net/l2tp/l2tp_core.h | 19 ++++++------- net/l2tp/l2tp_debugfs.c | 28 +++++++++--------- net/l2tp/l2tp_netlink.c | 72 ++++++++++++++++++----------------------------- net/l2tp/l2tp_ppp.c | 46 +++++++++++++++--------------- 5 files changed, 93 insertions(+), 147 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index c00f31b8cc04..97d30ac67c88 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -374,10 +374,8 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk struct sk_buff *skbp; struct sk_buff *tmp; u32 ns = L2TP_SKB_CB(skb)->ns; - struct l2tp_stats *sstats; spin_lock_bh(&session->reorder_q.lock); - sstats = &session->stats; skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { if (L2TP_SKB_CB(skbp)->ns > ns) { __skb_queue_before(&session->reorder_q, skbp, skb); @@ -385,9 +383,7 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", session->name, ns, L2TP_SKB_CB(skbp)->ns, skb_queue_len(&session->reorder_q)); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_oos_packets++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_oos_packets); goto out; } } @@ -404,23 +400,16 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff * { struct l2tp_tunnel *tunnel = session->tunnel; int length = L2TP_SKB_CB(skb)->length; - struct l2tp_stats *tstats, *sstats; /* We're about to requeue the skb, so return resources * to its current owner (a socket receive buffer). */ skb_orphan(skb); - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - sstats = &session->stats; - u64_stats_update_begin(&sstats->syncp); - tstats->rx_packets++; - tstats->rx_bytes += length; - sstats->rx_packets++; - sstats->rx_bytes += length; - u64_stats_update_end(&tstats->syncp); - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&tunnel->stats.rx_packets); + atomic_long_add(length, &tunnel->stats.rx_bytes); + atomic_long_inc(&session->stats.rx_packets); + atomic_long_add(length, &session->stats.rx_bytes); if (L2TP_SKB_CB(skb)->has_seq) { /* Bump our Nr */ @@ -451,7 +440,6 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) { struct sk_buff *skb; struct sk_buff *tmp; - struct l2tp_stats *sstats; /* If the pkt at the head of the queue has the nr that we * expect to send up next, dequeue it and any other @@ -459,13 +447,10 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) */ start: spin_lock_bh(&session->reorder_q.lock); - sstats = &session->stats; skb_queue_walk_safe(&session->reorder_q, skb, tmp) { if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - sstats->rx_errors++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); + atomic_long_inc(&session->stats.rx_errors); l2tp_dbg(session, L2TP_MSG_SEQ, "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n", session->name, L2TP_SKB_CB(skb)->ns, @@ -624,7 +609,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, struct l2tp_tunnel *tunnel = session->tunnel; int offset; u32 ns, nr; - struct l2tp_stats *sstats = &session->stats; /* The ref count is increased since we now hold a pointer to * the session. Take care to decrement the refcnt when exiting @@ -641,9 +625,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, "%s: cookie mismatch (%u/%u). Discarding.\n", tunnel->name, tunnel->tunnel_id, session->session_id); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_cookie_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_cookie_discards); goto discard; } ptr += session->peer_cookie_len; @@ -712,9 +694,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, l2tp_warn(session, L2TP_MSG_SEQ, "%s: recv data has no seq numbers when required. Discarding.\n", session->name); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); goto discard; } @@ -733,9 +713,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, l2tp_warn(session, L2TP_MSG_SEQ, "%s: recv data has no seq numbers when required. Discarding.\n", session->name); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); goto discard; } } @@ -789,9 +767,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, * packets */ if (L2TP_SKB_CB(skb)->ns != session->nr) { - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); l2tp_dbg(session, L2TP_MSG_SEQ, "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", session->name, L2TP_SKB_CB(skb)->ns, @@ -817,9 +793,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, return; discard: - u64_stats_update_begin(&sstats->syncp); - sstats->rx_errors++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_errors); kfree_skb(skb); if (session->deref) @@ -861,7 +835,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, u32 tunnel_id, session_id; u16 version; int length; - struct l2tp_stats *tstats; if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) goto discard_bad_csum; @@ -950,10 +923,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, discard_bad_csum: LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0); - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - tstats->rx_errors++; - u64_stats_update_end(&tstats->syncp); + atomic_long_inc(&tunnel->stats.rx_errors); kfree_skb(skb); return 0; @@ -1080,7 +1050,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, struct l2tp_tunnel *tunnel = session->tunnel; unsigned int len = skb->len; int error; - struct l2tp_stats *tstats, *sstats; /* Debug */ if (session->send_seq) @@ -1109,21 +1078,15 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, error = ip_queue_xmit(skb, fl); /* Update stats */ - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - sstats = &session->stats; - u64_stats_update_begin(&sstats->syncp); if (error >= 0) { - tstats->tx_packets++; - tstats->tx_bytes += len; - sstats->tx_packets++; - sstats->tx_bytes += len; + atomic_long_inc(&tunnel->stats.tx_packets); + atomic_long_add(len, &tunnel->stats.tx_bytes); + atomic_long_inc(&session->stats.tx_packets); + atomic_long_add(len, &session->stats.tx_bytes); } else { - tstats->tx_errors++; - sstats->tx_errors++; + atomic_long_inc(&tunnel->stats.tx_errors); + atomic_long_inc(&session->stats.tx_errors); } - u64_stats_update_end(&tstats->syncp); - u64_stats_update_end(&sstats->syncp); return 0; } diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index d40713d105fc..519b013f8b31 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -36,16 +36,15 @@ enum { struct sk_buff; struct l2tp_stats { - u64 tx_packets; - u64 tx_bytes; - u64 tx_errors; - u64 rx_packets; - u64 rx_bytes; - u64 rx_seq_discards; - u64 rx_oos_packets; - u64 rx_errors; - u64 rx_cookie_discards; - struct u64_stats_sync syncp; + atomic_long_t tx_packets; + atomic_long_t tx_bytes; + atomic_long_t tx_errors; + atomic_long_t rx_packets; + atomic_long_t rx_bytes; + atomic_long_t rx_seq_discards; + atomic_long_t rx_oos_packets; + atomic_long_t rx_errors; + atomic_long_t rx_cookie_discards; }; struct l2tp_tunnel; diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index c3813bc84552..072d7202e182 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -146,14 +146,14 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v) tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0, atomic_read(&tunnel->ref_count)); - seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n", + seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n", tunnel->debug, - (unsigned long long)tunnel->stats.tx_packets, - (unsigned long long)tunnel->stats.tx_bytes, - (unsigned long long)tunnel->stats.tx_errors, - (unsigned long long)tunnel->stats.rx_packets, - (unsigned long long)tunnel->stats.rx_bytes, - (unsigned long long)tunnel->stats.rx_errors); + atomic_long_read(&tunnel->stats.tx_packets), + atomic_long_read(&tunnel->stats.tx_bytes), + atomic_long_read(&tunnel->stats.tx_errors), + atomic_long_read(&tunnel->stats.rx_packets), + atomic_long_read(&tunnel->stats.rx_bytes), + atomic_long_read(&tunnel->stats.rx_errors)); if (tunnel->show != NULL) tunnel->show(m, tunnel); @@ -203,14 +203,14 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v) seq_printf(m, "\n"); } - seq_printf(m, " %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n", + seq_printf(m, " %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n", session->nr, session->ns, - (unsigned long long)session->stats.tx_packets, - (unsigned long long)session->stats.tx_bytes, - (unsigned long long)session->stats.tx_errors, - (unsigned long long)session->stats.rx_packets, - (unsigned long long)session->stats.rx_bytes, - (unsigned long long)session->stats.rx_errors); + atomic_long_read(&session->stats.tx_packets), + atomic_long_read(&session->stats.tx_bytes), + atomic_long_read(&session->stats.tx_errors), + atomic_long_read(&session->stats.rx_packets), + atomic_long_read(&session->stats.rx_bytes), + atomic_long_read(&session->stats.rx_errors)); if (session->show != NULL) session->show(m, session); diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index c1bab22db85e..0825ff26e113 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -246,8 +246,6 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla #if IS_ENABLED(CONFIG_IPV6) struct ipv6_pinfo *np = NULL; #endif - struct l2tp_stats stats; - unsigned int start; hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, L2TP_CMD_TUNNEL_GET); @@ -265,28 +263,22 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla if (nest == NULL) goto nla_put_failure; - do { - start = u64_stats_fetch_begin(&tunnel->stats.syncp); - stats.tx_packets = tunnel->stats.tx_packets; - stats.tx_bytes = tunnel->stats.tx_bytes; - stats.tx_errors = tunnel->stats.tx_errors; - stats.rx_packets = tunnel->stats.rx_packets; - stats.rx_bytes = tunnel->stats.rx_bytes; - stats.rx_errors = tunnel->stats.rx_errors; - stats.rx_seq_discards = tunnel->stats.rx_seq_discards; - stats.rx_oos_packets = tunnel->stats.rx_oos_packets; - } while (u64_stats_fetch_retry(&tunnel->stats.syncp, start)); - - if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) || - nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) || - nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) || - nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) || + if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, + atomic_long_read(&tunnel->stats.tx_packets)) || + nla_put_u64(skb, L2TP_ATTR_TX_BYTES, + atomic_long_read(&tunnel->stats.tx_bytes)) || + nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, + atomic_long_read(&tunnel->stats.tx_errors)) || + nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, + atomic_long_read(&tunnel->stats.rx_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_BYTES, + atomic_long_read(&tunnel->stats.rx_bytes)) || nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, - stats.rx_seq_discards) || + atomic_long_read(&tunnel->stats.rx_seq_discards)) || nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, - stats.rx_oos_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) + atomic_long_read(&tunnel->stats.rx_oos_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, + atomic_long_read(&tunnel->stats.rx_errors))) goto nla_put_failure; nla_nest_end(skb, nest); @@ -612,8 +604,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl struct nlattr *nest; struct l2tp_tunnel *tunnel = session->tunnel; struct sock *sk = NULL; - struct l2tp_stats stats; - unsigned int start; sk = tunnel->sock; @@ -656,28 +646,22 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl if (nest == NULL) goto nla_put_failure; - do { - start = u64_stats_fetch_begin(&session->stats.syncp); - stats.tx_packets = session->stats.tx_packets; - stats.tx_bytes = session->stats.tx_bytes; - stats.tx_errors = session->stats.tx_errors; - stats.rx_packets = session->stats.rx_packets; - stats.rx_bytes = session->stats.rx_bytes; - stats.rx_errors = session->stats.rx_errors; - stats.rx_seq_discards = session->stats.rx_seq_discards; - stats.rx_oos_packets = session->stats.rx_oos_packets; - } while (u64_stats_fetch_retry(&session->stats.syncp, start)); - - if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) || - nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) || - nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) || - nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) || + if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, + atomic_long_read(&session->stats.tx_packets)) || + nla_put_u64(skb, L2TP_ATTR_TX_BYTES, + atomic_long_read(&session->stats.tx_bytes)) || + nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, + atomic_long_read(&session->stats.tx_errors)) || + nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, + atomic_long_read(&session->stats.rx_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_BYTES, + atomic_long_read(&session->stats.rx_bytes)) || nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, - stats.rx_seq_discards) || + atomic_long_read(&session->stats.rx_seq_discards)) || nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, - stats.rx_oos_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) + atomic_long_read(&session->stats.rx_oos_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, + atomic_long_read(&session->stats.rx_errors))) goto nla_put_failure; nla_nest_end(skb, nest); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 7e3e16aefcb5..9d0eb8c13530 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -260,7 +260,7 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int session->name); /* Not bound. Nothing we can do, so discard. */ - session->stats.rx_errors++; + atomic_long_inc(&session->stats.rx_errors); kfree_skb(skb); } @@ -992,14 +992,14 @@ end: static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest, struct l2tp_stats *stats) { - dest->tx_packets = stats->tx_packets; - dest->tx_bytes = stats->tx_bytes; - dest->tx_errors = stats->tx_errors; - dest->rx_packets = stats->rx_packets; - dest->rx_bytes = stats->rx_bytes; - dest->rx_seq_discards = stats->rx_seq_discards; - dest->rx_oos_packets = stats->rx_oos_packets; - dest->rx_errors = stats->rx_errors; + dest->tx_packets = atomic_long_read(&stats->tx_packets); + dest->tx_bytes = atomic_long_read(&stats->tx_bytes); + dest->tx_errors = atomic_long_read(&stats->tx_errors); + dest->rx_packets = atomic_long_read(&stats->rx_packets); + dest->rx_bytes = atomic_long_read(&stats->rx_bytes); + dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards); + dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets); + dest->rx_errors = atomic_long_read(&stats->rx_errors); } /* Session ioctl helper. @@ -1633,14 +1633,14 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v) tunnel->name, (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N', atomic_read(&tunnel->ref_count) - 1); - seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n", + seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld\n", tunnel->debug, - (unsigned long long)tunnel->stats.tx_packets, - (unsigned long long)tunnel->stats.tx_bytes, - (unsigned long long)tunnel->stats.tx_errors, - (unsigned long long)tunnel->stats.rx_packets, - (unsigned long long)tunnel->stats.rx_bytes, - (unsigned long long)tunnel->stats.rx_errors); + atomic_long_read(&tunnel->stats.tx_packets), + atomic_long_read(&tunnel->stats.tx_bytes), + atomic_long_read(&tunnel->stats.tx_errors), + atomic_long_read(&tunnel->stats.rx_packets), + atomic_long_read(&tunnel->stats.rx_bytes), + atomic_long_read(&tunnel->stats.rx_errors)); } static void pppol2tp_seq_session_show(struct seq_file *m, void *v) @@ -1675,14 +1675,14 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v) session->lns_mode ? "LNS" : "LAC", session->debug, jiffies_to_msecs(session->reorder_timeout)); - seq_printf(m, " %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n", + seq_printf(m, " %hu/%hu %ld/%ld/%ld %ld/%ld/%ld\n", session->nr, session->ns, - (unsigned long long)session->stats.tx_packets, - (unsigned long long)session->stats.tx_bytes, - (unsigned long long)session->stats.tx_errors, - (unsigned long long)session->stats.rx_packets, - (unsigned long long)session->stats.rx_bytes, - (unsigned long long)session->stats.rx_errors); + atomic_long_read(&session->stats.tx_packets), + atomic_long_read(&session->stats.tx_bytes), + atomic_long_read(&session->stats.tx_errors), + atomic_long_read(&session->stats.rx_packets), + atomic_long_read(&session->stats.rx_bytes), + atomic_long_read(&session->stats.rx_errors)); if (po) seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); -- cgit v1.2.3 From f6e16b299bacaa71c6604a784f2d088a966f8c23 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 19 Mar 2013 06:11:23 +0000 Subject: l2tp: unhash l2tp sessions on delete, not on free If we postpone unhashing of l2tp sessions until the structure is freed, we risk: 1. further packets arriving and getting queued while the pseudowire is being closed down 2. the recv path hitting "scheduling while atomic" errors in the case that recv drops the last reference to a session and calls l2tp_session_free while in atomic context As such, l2tp sessions should be unhashed from l2tp_core data structures early in the teardown process prior to calling pseudowire close. For pseudowires like l2tp_ppp which have multiple shutdown codepaths, provide an unhash hook. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 75 ++++++++++++++++++++++++---------------------------- net/l2tp/l2tp_core.h | 1 + net/l2tp/l2tp_ppp.c | 12 +++------ 3 files changed, 38 insertions(+), 50 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 97d30ac67c88..8aecf5df6656 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1316,26 +1316,12 @@ again: hlist_del_init(&session->hlist); - /* Since we should hold the sock lock while - * doing any unbinding, we need to release the - * lock we're holding before taking that lock. - * Hold a reference to the sock so it doesn't - * disappear as we're jumping between locks. - */ if (session->ref != NULL) (*session->ref)(session); write_unlock_bh(&tunnel->hlist_lock); - if (tunnel->version != L2TP_HDR_VER_2) { - struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - - spin_lock_bh(&pn->l2tp_session_hlist_lock); - hlist_del_init_rcu(&session->global_hlist); - spin_unlock_bh(&pn->l2tp_session_hlist_lock); - synchronize_rcu(); - } - + __l2tp_session_unhash(session); l2tp_session_queue_purge(session); if (session->session_close != NULL) @@ -1732,64 +1718,71 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); */ void l2tp_session_free(struct l2tp_session *session) { - struct l2tp_tunnel *tunnel; + struct l2tp_tunnel *tunnel = session->tunnel; BUG_ON(atomic_read(&session->ref_count) != 0); - tunnel = session->tunnel; - if (tunnel != NULL) { + if (tunnel) { BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); + if (session->session_id != 0) + atomic_dec(&l2tp_session_count); + sock_put(tunnel->sock); + session->tunnel = NULL; + l2tp_tunnel_dec_refcount(tunnel); + } + + kfree(session); + + return; +} +EXPORT_SYMBOL_GPL(l2tp_session_free); + +/* Remove an l2tp session from l2tp_core's hash lists. + * Provides a tidyup interface for pseudowire code which can't just route all + * shutdown via. l2tp_session_delete and a pseudowire-specific session_close + * callback. + */ +void __l2tp_session_unhash(struct l2tp_session *session) +{ + struct l2tp_tunnel *tunnel = session->tunnel; - /* Delete the session from the hash */ + /* Remove the session from core hashes */ + if (tunnel) { + /* Remove from the per-tunnel hash */ write_lock_bh(&tunnel->hlist_lock); hlist_del_init(&session->hlist); write_unlock_bh(&tunnel->hlist_lock); - /* Unlink from the global hash if not L2TPv2 */ + /* For L2TPv3 we have a per-net hash: remove from there, too */ if (tunnel->version != L2TP_HDR_VER_2) { struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - spin_lock_bh(&pn->l2tp_session_hlist_lock); hlist_del_init_rcu(&session->global_hlist); spin_unlock_bh(&pn->l2tp_session_hlist_lock); synchronize_rcu(); } - - if (session->session_id != 0) - atomic_dec(&l2tp_session_count); - - sock_put(tunnel->sock); - - /* This will delete the tunnel context if this - * is the last session on the tunnel. - */ - session->tunnel = NULL; - l2tp_tunnel_dec_refcount(tunnel); } - - kfree(session); - - return; } -EXPORT_SYMBOL_GPL(l2tp_session_free); +EXPORT_SYMBOL_GPL(__l2tp_session_unhash); /* This function is used by the netlink SESSION_DELETE command and by pseudowire modules. */ int l2tp_session_delete(struct l2tp_session *session) { + if (session->ref) + (*session->ref)(session); + __l2tp_session_unhash(session); l2tp_session_queue_purge(session); - if (session->session_close != NULL) (*session->session_close)(session); - + if (session->deref) + (*session->ref)(session); l2tp_session_dec_refcount(session); - return 0; } EXPORT_SYMBOL_GPL(l2tp_session_delete); - /* We come here whenever a session's send_seq, cookie_len or * l2specific_len parameters are set. */ diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 519b013f8b31..485a490fd990 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -242,6 +242,7 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); +extern void __l2tp_session_unhash(struct l2tp_session *session); extern int l2tp_session_delete(struct l2tp_session *session); extern void l2tp_session_free(struct l2tp_session *session); extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 9d0eb8c13530..637a341c1e2d 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -466,19 +466,12 @@ static void pppol2tp_session_close(struct l2tp_session *session) */ static void pppol2tp_session_destruct(struct sock *sk) { - struct l2tp_session *session; - - if (sk->sk_user_data != NULL) { - session = sk->sk_user_data; - if (session == NULL) - goto out; - + struct l2tp_session *session = sk->sk_user_data; + if (session) { sk->sk_user_data = NULL; BUG_ON(session->magic != L2TP_SESSION_MAGIC); l2tp_session_dec_refcount(session); } - -out: return; } @@ -509,6 +502,7 @@ static int pppol2tp_release(struct socket *sock) /* Purge any queued data */ if (session != NULL) { + __l2tp_session_unhash(session); l2tp_session_queue_purge(session); sock_put(sk); } -- cgit v1.2.3 From 8ed781668dd49b608f1e67a22e3b445fd0c2cd6f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 19 Mar 2013 06:39:29 +0000 Subject: flow_keys: include thoff into flow_keys for later usage In skb_flow_dissect(), we perform a dissection of a skbuff. Since we're doing the work here anyway, also store thoff for a later usage, e.g. in the BPF filter. Suggested-by: Eric Dumazet Signed-off-by: Daniel Borkmann Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/flow_keys.h | 1 + net/core/flow_dissector.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h index 80461c1ae9ef..bb8271d487b7 100644 --- a/include/net/flow_keys.h +++ b/include/net/flow_keys.h @@ -9,6 +9,7 @@ struct flow_keys { __be32 ports; __be16 port16[2]; }; + u16 thoff; u8 ip_proto; }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 9d4c7201400d..e187bf06d673 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -140,6 +140,8 @@ ipv6: flow->ports = *ports; } + flow->thoff = (u16) nhoff; + return true; } EXPORT_SYMBOL(skb_flow_dissect); -- cgit v1.2.3 From 283951f95b067877ca5ea77afaa212bb1e0507b5 Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Tue, 19 Mar 2013 08:19:29 +0000 Subject: ipconfig: Fix newline handling in log message. When using ipconfig the logs currently look like: Single name server: [ 3.467270] IP-Config: Complete: [ 3.470613] device=eth0, hwaddr=ac:de:48:00:00:01, ipaddr=172.16.42.2, mask=255.255.255.0, gw=172.16.42.1 [ 3.480670] host=infigo-1, domain=, nis-domain=(none) [ 3.486166] bootserver=172.16.42.1, rootserver=172.16.42.1, rootpath= [ 3.492910] nameserver0=172.16.42.1[ 3.496853] ALSA device list: Three name servers: [ 3.496949] IP-Config: Complete: [ 3.500293] device=eth0, hwaddr=ac:de:48:00:00:01, ipaddr=172.16.42.2, mask=255.255.255.0, gw=172.16.42.1 [ 3.510367] host=infigo-1, domain=, nis-domain=(none) [ 3.515864] bootserver=172.16.42.1, rootserver=172.16.42.1, rootpath= [ 3.522635] nameserver0=172.16.42.1, nameserver1=172.16.42.100 [ 3.529149] , nameserver2=172.16.42.200 Fix newline handling for these cases Signed-off-by: Martin Fuzzey Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 98cbc6877019..bf6c5cf31aed 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1522,7 +1522,8 @@ static int __init ip_auto_config(void) } for (i++; i < CONF_NAMESERVERS_MAX; i++) if (ic_nameservers[i] != NONE) - pr_cont(", nameserver%u=%pI4\n", i, &ic_nameservers[i]); + pr_cont(", nameserver%u=%pI4", i, &ic_nameservers[i]); + pr_cont("\n"); #endif /* !SILENT */ return 0; -- cgit v1.2.3 From 0582b7d15f8a7ae53dd2128b8eb01567b3fd2277 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 19 Mar 2013 13:40:23 +0000 Subject: sh_eth: fix bitbang memory leak sh_mdio_init() allocates pointer to 'struct bb_info' but only stores it locally, so that sh_mdio_release() can't free it on driver unload. Add the pointer to 'struct bb_info' to 'struct sh_eth_private', so that sh_mdio_init() can save 'bitbang' variable for sh_mdio_release() to be able to free it later... Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 5 +++++ drivers/net/ethernet/renesas/sh_eth.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 33e96176e4d8..c87862812ead 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2220,6 +2220,7 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp) /* MDIO bus release function */ static int sh_mdio_release(struct net_device *ndev) { + struct sh_eth_private *mdp = netdev_priv(ndev); struct mii_bus *bus = dev_get_drvdata(&ndev->dev); /* unregister mdio bus */ @@ -2234,6 +2235,9 @@ static int sh_mdio_release(struct net_device *ndev) /* free bitbang info */ free_mdio_bitbang(bus); + /* free bitbang memory */ + kfree(mdp->bitbang); + return 0; } @@ -2262,6 +2266,7 @@ static int sh_mdio_init(struct net_device *ndev, int id, bitbang->ctrl.ops = &bb_ops; /* MII controller setting */ + mdp->bitbang = bitbang; mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!mdp->mii_bus) { ret = -ENOMEM; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index bae84fd2e73a..e6655678458e 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -705,6 +705,7 @@ struct sh_eth_private { const u16 *reg_offset; void __iomem *addr; void __iomem *tsu_addr; + struct bb_info *bitbang; u32 num_rx_ring; u32 num_tx_ring; dma_addr_t rx_desc_dma; -- cgit v1.2.3 From fc0c0900408e05758a0df17c1924ca837fafca5e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 19 Mar 2013 13:41:32 +0000 Subject: sh_eth: check TSU registers ioremap() error One must check the result of ioremap() -- in this case it prevents potential kernel oops when initializing TSU registers further on... Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index c87862812ead..bf5e3cf97c4d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2446,6 +2446,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev) } mdp->tsu_addr = ioremap(rtsu->start, resource_size(rtsu)); + if (mdp->tsu_addr == NULL) { + ret = -ENOMEM; + dev_err(&pdev->dev, "TSU ioremap failed.\n"); + goto out_release; + } mdp->port = devno % 2; ndev->features = NETIF_F_HW_VLAN_FILTER; } -- cgit v1.2.3 From fa90b077d72b4ea92706e86fdff7b5dca294caa3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 20 Mar 2013 02:21:48 +0000 Subject: lpc_eth: fix error return code in lpc_eth_drv_probe() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/nxp/lpc_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index c4122c86f829..efa29b712d5f 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1472,7 +1472,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ndev); - if (lpc_mii_init(pldat) != 0) + ret = lpc_mii_init(pldat); + if (ret) goto err_out_unregister_netdev; netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", -- cgit v1.2.3 From 896ee0eee6261e30c3623be931c3f621428947df Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 20 Mar 2013 05:19:24 +0000 Subject: net/irda: add missing error path release_sock call This makes sure that release_sock is called for all error conditions in irda_getsockopt. Signed-off-by: Kees Cook Reported-by: Brad Spengler Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- net/irda/af_irda.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index d07e3a626446..d28e7f014cc6 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -2583,8 +2583,10 @@ bed: NULL, NULL, NULL); /* Check if the we got some results */ - if (!self->cachedaddr) - return -EAGAIN; /* Didn't find any devices */ + if (!self->cachedaddr) { + err = -EAGAIN; /* Didn't find any devices */ + goto out; + } daddr = self->cachedaddr; /* Cleanup */ self->cachedaddr = 0; -- cgit v1.2.3 From da2191e31409d1058dcbed44e8f53e39a40e86b3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 Mar 2013 12:31:07 -0300 Subject: net: fec: Define indexes as 'unsigned int' Fix the following warnings that happen when building with W=1 option: drivers/net/ethernet/freescale/fec.c: In function 'fec_enet_free_buffers': drivers/net/ethernet/freescale/fec.c:1337:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] drivers/net/ethernet/freescale/fec.c: In function 'fec_enet_alloc_buffers': drivers/net/ethernet/freescale/fec.c:1361:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] drivers/net/ethernet/freescale/fec.c: In function 'fec_enet_init': drivers/net/ethernet/freescale/fec.c:1631:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index e3f39372ce25..911d0253dbb2 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -1332,7 +1332,7 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) static void fec_enet_free_buffers(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - int i; + unsigned int i; struct sk_buff *skb; struct bufdesc *bdp; @@ -1356,7 +1356,7 @@ static void fec_enet_free_buffers(struct net_device *ndev) static int fec_enet_alloc_buffers(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - int i; + unsigned int i; struct sk_buff *skb; struct bufdesc *bdp; @@ -1598,7 +1598,7 @@ static int fec_enet_init(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); struct bufdesc *cbd_base; struct bufdesc *bdp; - int i; + unsigned int i; /* Allocate memory for buffer descriptors. */ cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, -- cgit v1.2.3 From 9d73adf431e093b23fb4990f1ade11283cb67a98 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 Mar 2013 08:19:32 +0000 Subject: fec: Fix the build as module Since commit ff43da86c69 (NET: FEC: dynamtic check DMA desc buff type) the following build error happens when CONFIG_FEC=m ERROR: "fec_ptp_init" [drivers/net/ethernet/freescale/fec.ko] undefined! ERROR: "fec_ptp_ioctl" [drivers/net/ethernet/freescale/fec.ko] undefined! ERROR: "fec_ptp_start_cyclecounter" [drivers/net/ethernet/freescale/fec.ko] undefined! Fix it by exporting the required fec_ptp symbols. Reported-by: Uwe Kleine-Koenig Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_ptp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 1f17ca0f2201..0d8df400a479 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -128,6 +128,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev) spin_unlock_irqrestore(&fep->tmreg_lock, flags); } +EXPORT_SYMBOL(fec_ptp_start_cyclecounter); /** * fec_ptp_adjfreq - adjust ptp cycle frequency @@ -318,6 +319,7 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } +EXPORT_SYMBOL(fec_ptp_ioctl); /** * fec_time_keep - call timecounter_read every second to avoid timer overrun @@ -383,3 +385,4 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev) pr_info("registered PHC device on %s\n", ndev->name); } } +EXPORT_SYMBOL(fec_ptp_init); -- cgit v1.2.3 From 00aa0fac76c2f3b5a3543a63798af12c6d48b9b1 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 20 Mar 2013 17:37:32 +0100 Subject: ASoC: wm8903: Add the DAC boost control Signed-off-by: Alban Bedel Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 134e41c870b9..70e5eb200485 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -478,6 +478,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, /* ALSA can only do steps of .01dB */ static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); + static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); @@ -698,6 +700,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode), SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), SOC_ENUM("DAC Companding Mode", dac_companding), SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), +SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0, + dac_boost_tlv), SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, wm8903_get_deemph, wm8903_put_deemph), -- cgit v1.2.3 From cf4ab538f1516606d3ae730dce15d6f33d96b7e1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 8 Mar 2013 12:56:37 -0500 Subject: NFSv4: Fix the string length returned by the idmapper Functions like nfs_map_uid_to_name() and nfs_map_gid_to_group() are expected to return a string without any terminating NUL character. Regression introduced by commit 57e62324e469e092ecc6c94a7a86fe4bd6ac5172 (NFS: Store the legacy idmapper result in the keyring). Reported-by: Dave Chiluk Signed-off-by: Trond Myklebust Cc: Bryan Schumaker Cc: stable@vger.kernel.org [>=3.4] --- fs/nfs/idmap.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index dc0f98dfa717..c516da5873fd 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -726,9 +726,9 @@ out1: return ret; } -static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) +static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen) { - return key_instantiate_and_link(key, data, strlen(data) + 1, + return key_instantiate_and_link(key, data, datalen, id_resolver_cache->thread_keyring, authkey); } @@ -738,6 +738,7 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, struct key *key, struct key *authkey) { char id_str[NFS_UINT_MAXLEN]; + size_t len; int ret = -ENOKEY; /* ret = -ENOKEY */ @@ -747,13 +748,15 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, case IDMAP_CONV_NAMETOID: if (strcmp(upcall->im_name, im->im_name) != 0) break; - sprintf(id_str, "%d", im->im_id); - ret = nfs_idmap_instantiate(key, authkey, id_str); + /* Note: here we store the NUL terminator too */ + len = sprintf(id_str, "%d", im->im_id) + 1; + ret = nfs_idmap_instantiate(key, authkey, id_str, len); break; case IDMAP_CONV_IDTONAME: if (upcall->im_id != im->im_id) break; - ret = nfs_idmap_instantiate(key, authkey, im->im_name); + len = strlen(im->im_name); + ret = nfs_idmap_instantiate(key, authkey, im->im_name, len); break; default: ret = -EINVAL; -- cgit v1.2.3 From ce1eadda6badef9e4e3460097ede674fca47383d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Mar 2013 20:26:57 +0100 Subject: cfg80211: fix wdev tracing crash Arend reported a crash in tracing if the driver returns an ERR_PTR() value from the add_virtual_intf() callback. This is due to the tracing then still attempting to dereference the "pointer", fix this by using IS_ERR_OR_NULL(). Reported-by: Arend van Spriel Tested-by: Arend van Spriel Signed-off-by: Johannes Berg --- net/wireless/trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 6847d043edea..7586de77a2f8 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -27,7 +27,8 @@ #define WIPHY_PR_ARG __entry->wiphy_name #define WDEV_ENTRY __field(u32, id) -#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) +#define WDEV_ASSIGN (__entry->id) = (!IS_ERR_OR_NULL(wdev) \ + ? wdev->identifier : 0) #define WDEV_PR_FMT "wdev(%u)" #define WDEV_PR_ARG (__entry->id) -- cgit v1.2.3 From 8b305780ed0c49a49c6bd58a4372fd6b22a5a71e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Mar 2013 22:25:17 +0100 Subject: mac80211: fix virtual monitor interface locking The virtual monitor interface has a locking issue, it calls into the channel context code with the iflist mutex held which isn't allowed since it is usually acquired the other way around. The mutex is still required for the interface iteration, but need not be held across the channel calls. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index baaa8608e52d..3bfe2612c8c2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - int ret = 0; + int ret; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return 0; - mutex_lock(&local->iflist_mtx); + ASSERT_RTNL(); if (local->monitor_sdata) - goto out_unlock; + return 0; sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); - if (!sdata) { - ret = -ENOMEM; - goto out_unlock; - } + if (!sdata) + return -ENOMEM; /* set up data */ sdata->local = local; @@ -377,13 +375,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) if (WARN_ON(ret)) { /* ok .. stupid driver, it asked for this! */ kfree(sdata); - goto out_unlock; + return ret; } ret = ieee80211_check_queues(sdata); if (ret) { kfree(sdata); - goto out_unlock; + return ret; } ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, @@ -391,13 +389,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) if (ret) { drv_remove_interface(local, sdata); kfree(sdata); - goto out_unlock; + return ret; } + mutex_lock(&local->iflist_mtx); rcu_assign_pointer(local->monitor_sdata, sdata); - out_unlock: mutex_unlock(&local->iflist_mtx); - return ret; + + return 0; } static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) @@ -407,14 +406,20 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return; + ASSERT_RTNL(); + mutex_lock(&local->iflist_mtx); sdata = rcu_dereference_protected(local->monitor_sdata, lockdep_is_held(&local->iflist_mtx)); - if (!sdata) - goto out_unlock; + if (!sdata) { + mutex_unlock(&local->iflist_mtx); + return; + } rcu_assign_pointer(local->monitor_sdata, NULL); + mutex_unlock(&local->iflist_mtx); + synchronize_net(); ieee80211_vif_release_channel(sdata); @@ -422,8 +427,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) drv_remove_interface(local, sdata); kfree(sdata); - out_unlock: - mutex_unlock(&local->iflist_mtx); } /* -- cgit v1.2.3 From 73214f5d9f33b79918b1f7babddd5c8af28dd23d Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 19 Mar 2013 01:47:28 +0000 Subject: thermal: shorten too long mcast group name The original name is too long. Signed-off-by: Masatake YAMATO Signed-off-by: David S. Miller --- include/linux/thermal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index f0bd7f90a90d..e3c0ae9bb1fa 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -44,7 +44,7 @@ /* Adding event notification support elements */ #define THERMAL_GENL_FAMILY_NAME "thermal_event" #define THERMAL_GENL_VERSION 0x01 -#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group" +#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" /* Default Thermal Governor */ #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) -- cgit v1.2.3 From 991f76f837bf22c5bb07261cfd86525a0a96650c Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 20 Mar 2013 23:25:24 +0800 Subject: sysfs: fix race between readdir and lseek While readdir() is running, lseek() may set filp->f_pos as zero, then may leave filp->private_data pointing to one sysfs_dirent object without holding its reference counter, so the sysfs_dirent object may be used after free in next readdir(). This patch holds inode->i_mutex to avoid the problem since the lock is always held in readdir path. Reported-by: Dave Jones Tested-by: Sasha Levin Cc: Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2fbdff6be25c..c9e16608f486 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1058,10 +1058,21 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) return 0; } +static loff_t sysfs_dir_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file_inode(file); + loff_t ret; + + mutex_lock(&inode->i_mutex); + ret = generic_file_llseek(file, offset, whence); + mutex_unlock(&inode->i_mutex); + + return ret; +} const struct file_operations sysfs_dir_operations = { .read = generic_read_dir, .readdir = sysfs_readdir, .release = sysfs_dir_release, - .llseek = generic_file_llseek, + .llseek = sysfs_dir_llseek, }; -- cgit v1.2.3 From e5110f411d2ee35bf8d202ccca2e89c633060dca Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 20 Mar 2013 23:25:25 +0800 Subject: sysfs: handle failure path correctly for readdir() In case of 'if (filp->f_pos == 0 or 1)' of sysfs_readdir(), the failure from filldir() isn't handled, and the reference counter of the sysfs_dirent object pointed by filp->private_data will be released without clearing filp->private_data, so use after free bug will be triggered later. This patch returns immeadiately under the situation for fixing the bug, and it is reasonable to return from readdir() when filldir() fails. Reported-by: Dave Jones Tested-by: Sasha Levin Cc: Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index c9e16608f486..e14512678c9b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1020,6 +1020,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) ino = parent_sd->s_ino; if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; + else + return 0; } if (filp->f_pos == 1) { if (parent_sd->s_parent) @@ -1028,6 +1030,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) ino = parent_sd->s_ino; if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; + else + return 0; } mutex_lock(&sysfs_mutex); for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos); -- cgit v1.2.3 From 991155bacb91c988c45586525771758ddadd44ce Mon Sep 17 00:00:00 2001 From: Horia Geanta Date: Wed, 20 Mar 2013 16:31:38 +0200 Subject: Revert "crypto: talitos - add IPsec ESN support" This reverts commit e763eb699be723fb41af818118068c6b3afdaf8d. Current IPsec ESN implementation for authencesn(cbc(aes), hmac(sha)) (separate encryption and integrity algorithms) does not conform to RFC4303. ICV is generated by hashing the sequence SPI, SeqNum-High, SeqNum-Low, IV, Payload instead of SPI, SeqNum-Low, IV, Payload, SeqNum-High. Cc: # 3.8, 3.7 Reported-by: Chaoxing Lin Signed-off-by: Horia Geanta Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 09b184adf31b..5b2b5e61e4f9 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -1974,11 +1973,7 @@ struct talitos_alg_template { }; static struct talitos_alg_template driver_algs[] = { - /* - * AEAD algorithms. These use a single-pass ipsec_esp descriptor. - * authencesn(*,*) is also registered, although not present - * explicitly here. - */ + /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */ { .type = CRYPTO_ALG_TYPE_AEAD, .alg.crypto = { .cra_name = "authenc(hmac(sha1),cbc(aes))", @@ -2820,9 +2815,7 @@ static int talitos_probe(struct platform_device *ofdev) if (hw_supports(dev, driver_algs[i].desc_hdr_template)) { struct talitos_crypto_alg *t_alg; char *name = NULL; - bool authenc = false; -authencesn: t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2837,8 +2830,6 @@ authencesn: err = crypto_register_alg( &t_alg->algt.alg.crypto); name = t_alg->algt.alg.crypto.cra_driver_name; - authenc = authenc ? !authenc : - !(bool)memcmp(name, "authenc", 7); break; case CRYPTO_ALG_TYPE_AHASH: err = crypto_register_ahash( @@ -2851,25 +2842,8 @@ authencesn: dev_err(dev, "%s alg registration failed\n", name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - if (authenc) { - struct crypto_alg *alg = - &driver_algs[i].alg.crypto; - - name = alg->cra_name; - memmove(name + 10, name + 7, - strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - name = alg->cra_driver_name; - memmove(name + 10, name + 7, - strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - goto authencesn; - } - } } } if (!list_empty(&priv->alg_list)) -- cgit v1.2.3 From 246bbedb9aaf27e2207501d93a869023a439fce5 Mon Sep 17 00:00:00 2001 From: Horia Geanta Date: Wed, 20 Mar 2013 16:31:58 +0200 Subject: Revert "crypto: caam - add IPsec ESN support" This reverts commit 891104ed008e8646c7860fe5bc70b0aac55dcc6c. Current IPsec ESN implementation for authencesn(cbc(aes), hmac(sha)) (separate encryption and integrity algorithms) does not conform to RFC4303. ICV is generated by hashing the sequence SPI, SeqNum-High, SeqNum-Low, IV, Payload instead of SPI, SeqNum-Low, IV, Payload, SeqNum-High. Cc: # 3.8, 3.7 Reported-by: Chaoxing Lin Signed-off-by: Horia Geanta Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 27 ++------------------------- drivers/crypto/caam/compat.h | 1 - 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index b2a0a0726a54..cf268b14ae9a 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1650,11 +1650,7 @@ struct caam_alg_template { }; static struct caam_alg_template driver_algs[] = { - /* - * single-pass ipsec_esp descriptor - * authencesn(*,*) is also registered, although not present - * explicitly here. - */ + /* single-pass ipsec_esp descriptor */ { .name = "authenc(hmac(md5),cbc(aes))", .driver_name = "authenc-hmac-md5-cbc-aes-caam", @@ -2217,9 +2213,7 @@ static int __init caam_algapi_init(void) for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { /* TODO: check if h/w supports alg */ struct caam_crypto_alg *t_alg; - bool done = false; -authencesn: t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2233,25 +2227,8 @@ authencesn: dev_warn(ctrldev, "%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && - !memcmp(driver_algs[i].name, "authenc", 7) && - !done) { - char *name; - - name = driver_algs[i].name; - memmove(name + 10, name + 7, strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - name = driver_algs[i].driver_name; - memmove(name + 10, name + 7, strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - done = true; - goto authencesn; - } - } } if (!list_empty(&priv->alg_list)) dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index cf15e7813801..762aeff626ac 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 6c43a519610a5e11af5be707ad88391ce86129ba Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 20 Mar 2013 09:45:22 +0100 Subject: drivers/Kconfig: add several missing GENERIC_HARDIRQS dependencies With this patch an allmodconfig finally builds on s390 again. Fixes these build errors: ERROR: "devm_request_threaded_irq" [drivers/spi/spi-altera.ko] undefined! ERROR: "devm_request_threaded_irq" [drivers/media/platform/sh_veu.ko] undefined! ERROR: "devm_request_threaded_irq" [drivers/dma/dw_dmac.ko] undefined! Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/dma/Kconfig | 1 + drivers/media/platform/Kconfig | 2 +- drivers/spi/Kconfig | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 80b69971cf28..aeaea32bcfda 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -83,6 +83,7 @@ config INTEL_IOP_ADMA config DW_DMAC tristate "Synopsys DesignWare AHB DMA support" + depends on GENERIC_HARDIRQS select DMA_ENGINE default y if CPU_AT32AP7000 help diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 05d7b6333461..a0639e779973 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -204,7 +204,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f80eee74a311..2be0de920d67 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -55,6 +55,7 @@ comment "SPI Master Controller Drivers" config SPI_ALTERA tristate "Altera SPI Controller" + depends on GENERIC_HARDIRQS select SPI_BITBANG help This is the driver for the Altera SPI Controller. @@ -310,7 +311,7 @@ config SPI_PXA2XX_DMA config SPI_PXA2XX tristate "PXA2xx SSP SPI master" - depends on ARCH_PXA || PCI || ACPI + depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS select PXA_SSP if ARCH_PXA help This enables using a PXA2xx or Sodaville SSP port as a SPI master -- cgit v1.2.3 From 3bff6038f1938d2541943dfde604a9b92f347650 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 18 Mar 2013 16:01:30 +0100 Subject: s390/scm_block: fix printk format string Use hex digits when referring to scm addresses. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/block/scm_blk.c | 4 ++-- drivers/s390/block/scm_drv.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 5ac9c935c151..713f0185f96d 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -307,7 +307,7 @@ static void scm_blk_handle_error(struct scm_request *scmrq) case EQC_WR_PROHIBIT: spin_lock_irqsave(&bdev->lock, flags); if (bdev->state != SCM_WR_PROHIBIT) - pr_info("%lu: Write access to the SCM increment is suspended\n", + pr_info("%lx: Write access to the SCM increment is suspended\n", (unsigned long) bdev->scmdev->address); bdev->state = SCM_WR_PROHIBIT; spin_unlock_irqrestore(&bdev->lock, flags); @@ -445,7 +445,7 @@ void scm_blk_set_available(struct scm_blk_dev *bdev) spin_lock_irqsave(&bdev->lock, flags); if (bdev->state == SCM_WR_PROHIBIT) - pr_info("%lu: Write access to the SCM increment is restored\n", + pr_info("%lx: Write access to the SCM increment is restored\n", (unsigned long) bdev->scmdev->address); bdev->state = SCM_OPER; spin_unlock_irqrestore(&bdev->lock, flags); diff --git a/drivers/s390/block/scm_drv.c b/drivers/s390/block/scm_drv.c index 5f6180d6ff08..c98cf52d78d1 100644 --- a/drivers/s390/block/scm_drv.c +++ b/drivers/s390/block/scm_drv.c @@ -19,7 +19,7 @@ static void scm_notify(struct scm_device *scmdev, enum scm_event event) switch (event) { case SCM_CHANGE: - pr_info("%lu: The capabilities of the SCM increment changed\n", + pr_info("%lx: The capabilities of the SCM increment changed\n", (unsigned long) scmdev->address); SCM_LOG(2, "State changed"); SCM_LOG_STATE(2, scmdev); -- cgit v1.2.3 From 94f9852de86447088e8e3c12d8b5a8f996acee32 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 20 Mar 2013 13:40:54 +0100 Subject: s390/scm_blk: fix error return code in scm_blk_init() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/block/scm_blk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 713f0185f96d..e9b9c8392832 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -463,12 +463,15 @@ static int __init scm_blk_init(void) goto out; scm_major = ret; - if (scm_alloc_rqs(nr_requests)) + ret = scm_alloc_rqs(nr_requests); + if (ret) goto out_unreg; scm_debug = debug_register("scm_log", 16, 1, 16); - if (!scm_debug) + if (!scm_debug) { + ret = -ENOMEM; goto out_free; + } debug_register_view(scm_debug, &debug_hex_ascii_view); debug_set_level(scm_debug, 2); -- cgit v1.2.3 From b7fef2dd7217d9e3f35c948e87297451e55c9709 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 21 Mar 2013 08:24:11 +0100 Subject: s390/uaccess: fix clear_user_pt() The page table walker variant of clear_user() is supposed to copy the contents of the empty zero page to user space. However since 238ec4ef "[S390] zero page cache synonyms" empty_zero_page is not anymore the page itself but contains the pointer to the empty zero pages. Therefore the page table walker variant of clear_user() copied the address of the first empty zero page and afterwards more or less random data to user space instead of clearing the given user space range. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/lib/uaccess_pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index dff631d34b45..6771fdd89377 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -197,7 +197,7 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from) static size_t clear_user_pt(size_t n, void __user *to) { - void *zpage = &empty_zero_page; + void *zpage = (void *) empty_zero_page; long done, size, ret; done = 0; -- cgit v1.2.3 From 1fcbba3d65dff8ce9d25e644fcc86fa8c629de7d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 21 Mar 2013 13:07:18 +0100 Subject: s390/3270: fix minor_start issue The 3270 device nodes 227/0 and 228/0 are special. 227/0 is never used, and 228/0 is used to redirect full screen applications from /dev/3270/tub to the real device node of the 3270 terminal. To keep the device names /dev/3270/tty consistent with the minor number the device driver sets minor_start to 0 and skips minor 0. That makes the tty index equivalent to the minor number. But doing so seems to causes problems with init scripts. A better solution is to set minor_start to the correct value of 1 and set name_base to 1 as well. tty_register_device will then automatically create the correct tty name. Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tty3270.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index b907dba24025..cee69dac3e18 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -915,7 +915,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) int i, rc; /* Check if the tty3270 is already there. */ - view = raw3270_find_view(&tty3270_fn, tty->index); + view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); if (!IS_ERR(view)) { tp = container_of(view, struct tty3270, view); tty->driver_data = tp; @@ -927,15 +927,16 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) tp->inattr = TF_INPUT; return tty_port_install(&tp->port, driver, tty); } - if (tty3270_max_index < tty->index) - tty3270_max_index = tty->index; + if (tty3270_max_index < tty->index + 1) + tty3270_max_index = tty->index + 1; /* Allocate tty3270 structure on first open. */ tp = tty3270_alloc_view(); if (IS_ERR(tp)) return PTR_ERR(tp); - rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index); + rc = raw3270_add_view(&tp->view, &tty3270_fn, + tty->index + RAW3270_FIRSTMINOR); if (rc) { tty3270_free_view(tp); return rc; @@ -1846,12 +1847,12 @@ static const struct tty_operations tty3270_ops = { void tty3270_create_cb(int minor) { - tty_register_device(tty3270_driver, minor, NULL); + tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL); } void tty3270_destroy_cb(int minor) { - tty_unregister_device(tty3270_driver, minor); + tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR); } struct raw3270_notifier tty3270_notifier = @@ -1884,7 +1885,8 @@ static int __init tty3270_init(void) driver->driver_name = "tty3270"; driver->name = "3270/tty"; driver->major = IBM_TTY3270_MAJOR; - driver->minor_start = 0; + driver->minor_start = RAW3270_FIRSTMINOR; + driver->name_base = RAW3270_FIRSTMINOR; driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; -- cgit v1.2.3 From ed9dc8ce7a1c8115dba9483a9b51df8b63a2e0ef Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Thu, 7 Mar 2013 11:40:17 -0600 Subject: efivars: Allow disabling use as a pstore backend Add a new option, CONFIG_EFI_VARS_PSTORE, which can be set to N to avoid using efivars as a backend to pstore, as some users may want to compile out the code completely. Set the default to Y to maintain backwards compatability, since this feature has always been enabled until now. Signed-off-by: Seth Forshee Cc: Josh Boyer Cc: Matthew Garrett Cc: Seiji Aguchi Cc: Tony Luck Cc: Signed-off-by: Matt Fleming --- drivers/firmware/Kconfig | 9 +++++++ drivers/firmware/efivars.c | 64 +++++++++++++++------------------------------- 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 9b00072a020f..898023d8e486 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -53,6 +53,15 @@ config EFI_VARS Subsequent efibootmgr releases may be found at: +config EFI_VARS_PSTORE + bool "Register efivars backend for pstore" + depends on EFI_VARS && PSTORE + default y + help + Say Y here to enable use efivars as a backend to pstore. This + will allow writing console messages, crash dumps, or anything + else supported by pstore to EFI variables. + config EFI_PCDP bool "Console device selection via EFI PCDP or HCDP table" depends on ACPI && EFI && IA64 diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index fe62aa392239..37b6f247399e 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -1309,9 +1309,7 @@ static const struct inode_operations efivarfs_dir_inode_operations = { .create = efivarfs_create, }; -static struct pstore_info efi_pstore_info; - -#ifdef CONFIG_PSTORE +#ifdef CONFIG_EFI_VARS_PSTORE static int efi_pstore_open(struct pstore_info *psi) { @@ -1514,38 +1512,6 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, return 0; } -#else -static int efi_pstore_open(struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_close(struct pstore_info *psi) -{ - return 0; -} - -static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, int *count, - struct timespec *timespec, - char **buf, struct pstore_info *psi) -{ - return -1; -} - -static int efi_pstore_write(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, int count, size_t size, - struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, - struct timespec time, struct pstore_info *psi) -{ - return 0; -} -#endif static struct pstore_info efi_pstore_info = { .owner = THIS_MODULE, @@ -1557,6 +1523,24 @@ static struct pstore_info efi_pstore_info = { .erase = efi_pstore_erase, }; +static void efivar_pstore_register(struct efivars *efivars) +{ + efivars->efi_pstore_info = efi_pstore_info; + efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); + if (efivars->efi_pstore_info.buf) { + efivars->efi_pstore_info.bufsize = 1024; + efivars->efi_pstore_info.data = efivars; + spin_lock_init(&efivars->efi_pstore_info.buf_lock); + pstore_register(&efivars->efi_pstore_info); + } +} +#else +static void efivar_pstore_register(struct efivars *efivars) +{ + return; +} +#endif + static ssize_t efivar_create(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -2025,15 +2009,7 @@ int register_efivars(struct efivars *efivars, if (error) unregister_efivars(efivars); - efivars->efi_pstore_info = efi_pstore_info; - - efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); - if (efivars->efi_pstore_info.buf) { - efivars->efi_pstore_info.bufsize = 1024; - efivars->efi_pstore_info.data = efivars; - spin_lock_init(&efivars->efi_pstore_info.buf_lock); - pstore_register(&efivars->efi_pstore_info); - } + efivar_pstore_register(efivars); register_filesystem(&efivarfs_type); -- cgit v1.2.3 From ec0971ba5372a4dfa753f232449d23a8fd98490e Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Mon, 11 Mar 2013 16:17:50 -0500 Subject: efivars: Add module parameter to disable use as a pstore backend We know that with some firmware implementations writing too much data to UEFI variables can lead to bricking machines. Recent changes attempt to address this issue, but for some it may still be prudent to avoid writing large amounts of data until the solution has been proven on a wide variety of hardware. Crash dumps or other data from pstore can potentially be a large data source. Add a pstore_module parameter to efivars to allow disabling its use as a backend for pstore. Also add a config option, CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE, to allow setting the default value of this paramter to true (i.e. disabled by default). Signed-off-by: Seth Forshee Cc: Josh Boyer Cc: Matthew Garrett Cc: Seiji Aguchi Cc: Tony Luck Cc: Signed-off-by: Matt Fleming --- drivers/firmware/Kconfig | 9 +++++++++ drivers/firmware/efivars.c | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 898023d8e486..42c759a4d047 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -62,6 +62,15 @@ config EFI_VARS_PSTORE will allow writing console messages, crash dumps, or anything else supported by pstore to EFI variables. +config EFI_VARS_PSTORE_DEFAULT_DISABLE + bool "Disable using efivars as a pstore backend by default" + depends on EFI_VARS_PSTORE + default n + help + Saying Y here will disable the use of efivars as a storage + backend for pstore by default. This setting can be overridden + using the efivars module's pstore_disable parameter. + config EFI_PCDP bool "Console device selection via EFI PCDP or HCDP table" depends on ACPI && EFI && IA64 diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 37b6f247399e..6607daf5a08d 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -103,6 +103,11 @@ MODULE_VERSION(EFIVARS_VERSION); */ #define GUID_LEN 36 +static bool efivars_pstore_disable = + IS_ENABLED(EFI_VARS_PSTORE_DEFAULT_DISABLE); + +module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); + /* * The maximum size of VariableName + Data = 1024 * Therefore, it's reasonable to save that much @@ -2009,7 +2014,8 @@ int register_efivars(struct efivars *efivars, if (error) unregister_efivars(efivars); - efivar_pstore_register(efivars); + if (!efivars_pstore_disable) + efivar_pstore_register(efivars); register_filesystem(&efivarfs_type); -- cgit v1.2.3 From ec50bd32f1672d38ddce10fb1841cbfda89cfe9a Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 1 Mar 2013 14:49:12 +0000 Subject: efivars: explicitly calculate length of VariableName It's not wise to assume VariableNameSize represents the length of VariableName, as not all firmware updates VariableNameSize in the same way (some don't update it at all if EFI_SUCCESS is returned). There are even implementations out there that update VariableNameSize with values that are both larger than the string returned in VariableName and smaller than the buffer passed to GetNextVariableName(), which resulted in the following bug report from Michael Schroeder, > On HP z220 system (firmware version 1.54), some EFI variables are > incorrectly named : > > ls -d /sys/firmware/efi/vars/*8be4d* | grep -v -- -8be returns > /sys/firmware/efi/vars/dbxDefault-pport8be4df61-93ca-11d2-aa0d-00e098032b8c > /sys/firmware/efi/vars/KEKDefault-pport8be4df61-93ca-11d2-aa0d-00e098032b8c > /sys/firmware/efi/vars/SecureBoot-pport8be4df61-93ca-11d2-aa0d-00e098032b8c > /sys/firmware/efi/vars/SetupMode-Information8be4df61-93ca-11d2-aa0d-00e098032b8c The issue here is that because we blindly use VariableNameSize without verifying its value, we can potentially read garbage values from the buffer containing VariableName if VariableNameSize is larger than the length of VariableName. Since VariableName is a string, we can calculate its size by searching for the terminating NULL character. Reported-by: Frederic Crozat Cc: Matthew Garrett Cc: Josh Boyer Cc: Michael Schroeder Cc: Lee, Chun-Yi Cc: Lingzhu Xiang Cc: Seiji Aguchi Signed-off-by: Matt Fleming --- drivers/firmware/efivars.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 6607daf5a08d..1e9d9b9d7a12 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -1705,6 +1705,31 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) return found; } +/* + * Returns the size of variable_name, in bytes, including the + * terminating NULL character, or variable_name_size if no NULL + * character is found among the first variable_name_size bytes. + */ +static unsigned long var_name_strnsize(efi_char16_t *variable_name, + unsigned long variable_name_size) +{ + unsigned long len; + efi_char16_t c; + + /* + * The variable name is, by definition, a NULL-terminated + * string, so make absolutely sure that variable_name_size is + * the value we expect it to be. If not, return the real size. + */ + for (len = 2; len <= variable_name_size; len += sizeof(c)) { + c = variable_name[(len / sizeof(c)) - 1]; + if (!c) + break; + } + + return min(len, variable_name_size); +} + static void efivar_update_sysfs_entries(struct work_struct *work) { struct efivars *efivars = &__efivars; @@ -1745,10 +1770,13 @@ static void efivar_update_sysfs_entries(struct work_struct *work) if (!found) { kfree(variable_name); break; - } else + } else { + variable_name_size = var_name_strnsize(variable_name, + variable_name_size); efivar_create_sysfs_entry(efivars, variable_name_size, variable_name, &vendor); + } } } @@ -1995,6 +2023,8 @@ int register_efivars(struct efivars *efivars, &vendor_guid); switch (status) { case EFI_SUCCESS: + variable_name_size = var_name_strnsize(variable_name, + variable_name_size); efivar_create_sysfs_entry(efivars, variable_name_size, variable_name, -- cgit v1.2.3 From e971318bbed610e28bb3fde9d548e6aaf0a6b02e Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 7 Mar 2013 11:59:14 +0000 Subject: efivars: Handle duplicate names from get_next_variable() Some firmware exhibits a bug where the same VariableName and VendorGuid values are returned on multiple invocations of GetNextVariableName(). See, https://bugzilla.kernel.org/show_bug.cgi?id=47631 As a consequence of such a bug, Andre reports hitting the following WARN_ON() in the sysfs code after updating the BIOS on his, "Gigabyte Technology Co., Ltd. To be filled by O.E.M./Z77X-UD3H, BIOS F19e 11/21/2012)" machine, [ 0.581554] EFI Variables Facility v0.08 2004-May-17 [ 0.584914] ------------[ cut here ]------------ [ 0.585639] WARNING: at /home/andre/linux/fs/sysfs/dir.c:536 sysfs_add_one+0xd4/0x100() [ 0.586381] Hardware name: To be filled by O.E.M. [ 0.587123] sysfs: cannot create duplicate filename '/firmware/efi/vars/SbAslBufferPtrVar-01f33c25-764d-43ea-aeea-6b5a41f3f3e8' [ 0.588694] Modules linked in: [ 0.589484] Pid: 1, comm: swapper/0 Not tainted 3.8.0+ #7 [ 0.590280] Call Trace: [ 0.591066] [] ? sysfs_add_one+0xd4/0x100 [ 0.591861] [] warn_slowpath_common+0x7f/0xc0 [ 0.592650] [] warn_slowpath_fmt+0x4c/0x50 [ 0.593429] [] ? strlcat+0x65/0x80 [ 0.594203] [] sysfs_add_one+0xd4/0x100 [ 0.594979] [] create_dir+0x78/0xd0 [ 0.595753] [] sysfs_create_dir+0x86/0xe0 [ 0.596532] [] kobject_add_internal+0x9c/0x220 [ 0.597310] [] kobject_init_and_add+0x67/0x90 [ 0.598083] [] ? efivar_create_sysfs_entry+0x61/0x1c0 [ 0.598859] [] efivar_create_sysfs_entry+0x11b/0x1c0 [ 0.599631] [] register_efivars+0xde/0x420 [ 0.600395] [] ? edd_init+0x2f5/0x2f5 [ 0.601150] [] efivars_init+0xb8/0x104 [ 0.601903] [] do_one_initcall+0x12a/0x180 [ 0.602659] [] kernel_init_freeable+0x13e/0x1c6 [ 0.603418] [] ? loglevel+0x31/0x31 [ 0.604183] [] ? rest_init+0x80/0x80 [ 0.604936] [] kernel_init+0xe/0xf0 [ 0.605681] [] ret_from_fork+0x7c/0xb0 [ 0.606414] [] ? rest_init+0x80/0x80 [ 0.607143] ---[ end trace 1609741ab737eb29 ]--- There's not much we can do to work around and keep traversing the variable list once we hit this firmware bug. Our only solution is to terminate the loop because, as Lingzhu reports, some machines get stuck when they encounter duplicate names, > I had an IBM System x3100 M4 and x3850 X5 on which kernel would > get stuck in infinite loop creating duplicate sysfs files because, > for some reason, there are several duplicate boot entries in nvram > getting GetNextVariableName into a circle of iteration (with > period > 2). Also disable the workqueue, as efivar_update_sysfs_entries() uses GetNextVariableName() to figure out which variables have been created since the last iteration. That algorithm isn't going to work if GetNextVariableName() returns duplicates. Note that we don't disable EFI variable creation completely on the affected machines, it's just that any pstore dump-* files won't appear in sysfs until the next boot. Reported-by: Andre Heider Reported-by: Lingzhu Xiang Tested-by: Lingzhu Xiang Cc: Seiji Aguchi Cc: Signed-off-by: Matt Fleming --- drivers/firmware/efivars.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 1e9d9b9d7a12..d64661fda4fd 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -170,6 +170,7 @@ efivar_create_sysfs_entry(struct efivars *efivars, static void efivar_update_sysfs_entries(struct work_struct *); static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); +static bool efivar_wq_enabled = true; /* Return the number of unicode characters in data */ static unsigned long @@ -1444,7 +1445,7 @@ static int efi_pstore_write(enum pstore_type_id type, spin_unlock_irqrestore(&efivars->lock, flags); - if (reason == KMSG_DUMP_OOPS) + if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) schedule_work(&efivar_work); *id = part; @@ -1975,6 +1976,35 @@ void unregister_efivars(struct efivars *efivars) } EXPORT_SYMBOL_GPL(unregister_efivars); +/* + * Print a warning when duplicate EFI variables are encountered and + * disable the sysfs workqueue since the firmware is buggy. + */ +static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, + unsigned long len16) +{ + size_t i, len8 = len16 / sizeof(efi_char16_t); + char *s8; + + /* + * Disable the workqueue since the algorithm it uses for + * detecting new variables won't work with this buggy + * implementation of GetNextVariableName(). + */ + efivar_wq_enabled = false; + + s8 = kzalloc(len8, GFP_KERNEL); + if (!s8) + return; + + for (i = 0; i < len8; i++) + s8[i] = s16[i]; + + printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", + s8, vendor_guid); + kfree(s8); +} + int register_efivars(struct efivars *efivars, const struct efivar_operations *ops, struct kobject *parent_kobj) @@ -2025,6 +2055,22 @@ int register_efivars(struct efivars *efivars, case EFI_SUCCESS: variable_name_size = var_name_strnsize(variable_name, variable_name_size); + + /* + * Some firmware implementations return the + * same variable name on multiple calls to + * get_next_variable(). Terminate the loop + * immediately as there is no guarantee that + * we'll ever see a different variable name, + * and may end up looping here forever. + */ + if (variable_is_present(variable_name, &vendor_guid)) { + dup_variable_bug(variable_name, &vendor_guid, + variable_name_size); + status = EFI_NOT_FOUND; + break; + } + efivar_create_sysfs_entry(efivars, variable_name_size, variable_name, -- cgit v1.2.3 From 4376c94618c26225e69e17b7c91169c45a90b292 Mon Sep 17 00:00:00 2001 From: fanchaoting Date: Thu, 21 Mar 2013 09:15:30 +0800 Subject: pnfs-block: removing DM device maybe cause oops when call dev_remove when pnfs block using device mapper,if umounting later,it maybe cause oops. we apply "1 + sizeof(bl_umount_request)" memory for msg->data, the memory maybe overflow when we do "memcpy(&dataptr [sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request))", because the size of bl_msg is more than 1 byte. Signed-off-by: fanchaoting Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayoutdm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 737d839bc17b..6fc7b5cae92b 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev) bl_pipe_msg.bl_wq = &nn->bl_wq; memset(msg, 0, sizeof(*msg)); - msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); + msg->len = sizeof(bl_msg) + bl_msg.totallen; + msg->data = kzalloc(msg->len, GFP_NOFS); if (!msg->data) goto out; @@ -66,7 +67,6 @@ static void dev_remove(struct net *net, dev_t dev) memcpy(msg->data, &bl_msg, sizeof(bl_msg)); dataptr = (uint8_t *) msg->data; memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); - msg->len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&nn->bl_wq, &wq); if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { -- cgit v1.2.3 From a073dbff359f4741013ae4b8395f5364c5e00b48 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 20 Mar 2013 12:34:32 -0400 Subject: NFSv4.1: Fix a race in pNFS layoutcommit We need to clear the NFS_LSEG_LAYOUTCOMMIT bits atomically with the NFS_INO_LAYOUTCOMMIT bit, otherwise we may end up with situations where the two are out of sync. The first half of the problem is to ensure that pnfs_layoutcommit_inode clears the NFS_LSEG_LAYOUTCOMMIT bit through pnfs_list_write_lseg. We still need to keep the reference to those segments until the RPC call is finished, so in order to make it clear _where_ those references come from, we add a helper pnfs_list_write_lseg_done() that cleans up after pnfs_list_write_lseg. Signed-off-by: Trond Myklebust Acked-by: Benny Halevy Cc: stable@vger.kernel.org --- fs/nfs/nfs4proc.c | 14 -------------- fs/nfs/pnfs.c | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b2671cb0f901..6ccdd4fd9b59 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6416,22 +6416,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) static void nfs4_layoutcommit_release(void *calldata) { struct nfs4_layoutcommit_data *data = calldata; - struct pnfs_layout_segment *lseg, *tmp; - unsigned long *bitlock = &NFS_I(data->args.inode)->flags; pnfs_cleanup_layoutcommit(data); - /* Matched by references in pnfs_set_layoutcommit */ - list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { - list_del_init(&lseg->pls_lc_list); - if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, - &lseg->pls_flags)) - pnfs_put_lseg(lseg); - } - - clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); - wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); - put_rpccred(data->cred); kfree(data); } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 48ac5aad6258..3d900916fd41 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1746,11 +1746,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { if (lseg->pls_range.iomode == IOMODE_RW && - test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) list_add(&lseg->pls_lc_list, listp); } } +static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) +{ + struct pnfs_layout_segment *lseg, *tmp; + unsigned long *bitlock = &NFS_I(inode)->flags; + + /* Matched by references in pnfs_set_layoutcommit */ + list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { + list_del_init(&lseg->pls_lc_list); + pnfs_put_lseg(lseg); + } + + clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); + smp_mb__after_clear_bit(); + wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); +} + void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) { pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); @@ -1795,6 +1811,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data) if (nfss->pnfs_curr_ld->cleanup_layoutcommit) nfss->pnfs_curr_ld->cleanup_layoutcommit(data); + pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list); } /* -- cgit v1.2.3 From 24956804349ca0eadcdde032d65e8c00b4214096 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 20 Mar 2013 13:03:00 -0400 Subject: NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn Note that clearing NFS_INO_LAYOUTCOMMIT is tricky, since it requires you to also clear the NFS_LSEG_LAYOUTCOMMIT bits from the layout segments. The only two sites that need to do this are the ones that call pnfs_return_layout() without first doing a layout commit. Signed-off-by: Trond Myklebust Acked-by: Benny Halevy Cc: stable@vger.kernel.org --- fs/nfs/nfs4filelayout.c | 1 - fs/nfs/pnfs.c | 35 +++++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 49eeb044c109..4fb234d3aefb 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) { if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) return; - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); pnfs_return_layout(inode); } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3d900916fd41..5044142c1216 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range, lo_seg_intersecting(lseg_range, recall_range); } +static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, + struct list_head *tmp_list) +{ + if (!atomic_dec_and_test(&lseg->pls_refcount)) + return false; + pnfs_layout_remove_lseg(lseg->pls_layout, lseg); + list_add(&lseg->pls_list, tmp_list); + return true; +} + /* Returns 1 if lseg is removed from list, 0 otherwise */ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, struct list_head *tmp_list) @@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, */ dprintk("%s: lseg %p ref %d\n", __func__, lseg, atomic_read(&lseg->pls_refcount)); - if (atomic_dec_and_test(&lseg->pls_refcount)) { - pnfs_layout_remove_lseg(lseg->pls_layout, lseg); - list_add(&lseg->pls_list, tmp_list); + if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) rv = 1; - } } return rv; } @@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo, return lseg; } +static void pnfs_clear_layoutcommit(struct inode *inode, + struct list_head *head) +{ + struct nfs_inode *nfsi = NFS_I(inode); + struct pnfs_layout_segment *lseg, *tmp; + + if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) + return; + list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { + if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + continue; + pnfs_lseg_dec_and_remove_zero(lseg, head); + } +} + /* * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr * when the layout segment list is empty. @@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino) /* Reference matched in nfs4_layoutreturn_release */ pnfs_get_layout_hdr(lo); empty = list_empty(&lo->plh_segs); + pnfs_clear_layoutcommit(ino, &tmp_list); pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); /* Don't send a LAYOUTRETURN if list was initially empty */ if (empty) { @@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino) spin_unlock(&ino->i_lock); pnfs_free_lseg_list(&tmp_list); - WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); - lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); if (unlikely(lrp == NULL)) { status = -ENOMEM; @@ -1458,7 +1479,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) dprintk("pnfs write error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) @@ -1613,7 +1633,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) dprintk("pnfs read error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) -- cgit v1.2.3 From 240286725d854331422cb15957f8d9bf2741d4e3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 20 Mar 2013 13:23:33 -0400 Subject: NFSv4.1: Add a helper pnfs_commit_and_return_layout In order to be able to safely return the layout in nfs4_proc_setattr, we need to block new uses of the layout, wait for all outstanding users of the layout to complete, commit the layout and then return it. This patch adds a helper in order to do all this safely. Signed-off-by: Trond Myklebust Cc: Boaz Harrosh --- fs/nfs/nfs4proc.c | 2 +- fs/nfs/pnfs.c | 27 +++++++++++++++++++++++++++ fs/nfs/pnfs.h | 6 ++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6ccdd4fd9b59..26431cf62ddb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, int status; if (pnfs_ld_layoutret_on_setattr(inode)) - pnfs_return_layout(inode); + pnfs_commit_and_return_layout(inode); nfs_fattr_init(fattr); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 5044142c1216..4bdffe0ba025 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -866,6 +866,33 @@ out: } EXPORT_SYMBOL_GPL(_pnfs_return_layout); +int +pnfs_commit_and_return_layout(struct inode *inode) +{ + struct pnfs_layout_hdr *lo; + int ret; + + spin_lock(&inode->i_lock); + lo = NFS_I(inode)->layout; + if (lo == NULL) { + spin_unlock(&inode->i_lock); + return 0; + } + pnfs_get_layout_hdr(lo); + /* Block new layoutgets and read/write to ds */ + lo->plh_block_lgets++; + spin_unlock(&inode->i_lock); + filemap_fdatawait(inode->i_mapping); + ret = pnfs_layoutcommit_inode(inode, true); + if (ret == 0) + ret = _pnfs_return_layout(inode); + spin_lock(&inode->i_lock); + lo->plh_block_lgets--; + spin_unlock(&inode->i_lock); + pnfs_put_layout_hdr(lo); + return ret; +} + bool pnfs_roc(struct inode *ino) { struct pnfs_layout_hdr *lo; diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 94ba80417748..f5f8a470a647 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata); void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); int pnfs_layoutcommit_inode(struct inode *inode, bool sync); int _pnfs_return_layout(struct inode *); +int pnfs_commit_and_return_layout(struct inode *); void pnfs_ld_write_done(struct nfs_write_data *); void pnfs_ld_read_done(struct nfs_read_data *); struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, @@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino) return 0; } +static inline int pnfs_commit_and_return_layout(struct inode *inode) +{ + return 0; +} + static inline bool pnfs_ld_layoutret_on_setattr(struct inode *inode) { -- cgit v1.2.3 From cb0e51d80694fc9964436be1a1a15275e991cb1e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 20 Mar 2013 21:31:42 +0000 Subject: lantiq_etop: use free_netdev(netdev) instead of kfree() Freeing netdev without free_netdev() leads to net, tx leaks. And it may lead to dereferencing freed pointer. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/lantiq_etop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 6a2127489af7..bfdb06860397 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -769,7 +769,7 @@ ltq_etop_probe(struct platform_device *pdev) return 0; err_free: - kfree(dev); + free_netdev(dev); err_out: return err; } -- cgit v1.2.3 From ce16294fda230c787ce5c35f61b2f80d14d70a72 Mon Sep 17 00:00:00 2001 From: Lothar Waßmann Date: Thu, 21 Mar 2013 02:20:11 +0000 Subject: net: ethernet: cpsw: fix erroneous condition in error check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error check in cpsw_probe_dt() has an '&&' where an '||' is meant to be. This causes a NULL pointer dereference when incomplet DT data is passed to the driver ('phy_id' property for cpsw_emac1 missing). Signed-off-by: Lothar Waßmann Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 75c48558e6fd..df32a090d08e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1364,7 +1364,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, struct platform_device *mdio; parp = of_get_property(slave_node, "phy_id", &lenp); - if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { + if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { pr_err("Missing slave[%d] phy_id property\n", i); ret = -EINVAL; goto error_ret; -- cgit v1.2.3 From c101c81b5293cdcb616ed4948d0c4a4cfd1f481a Mon Sep 17 00:00:00 2001 From: Moshe Lazer Date: Thu, 21 Mar 2013 05:55:51 +0000 Subject: net/mlx4_core: Fix wrong mask applied on EQ numbers in the wrapper Currently the mask is wrongly set in the MAP_EQ wrapper, fix that. Without the fix any EQ number above 511 is mapped to one below 511. Signed-off-by: Moshe Lazer Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/eq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 251ae2f93116..8e3123a1df88 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -771,7 +771,7 @@ int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_slave_event_eq_info *event_eq = priv->mfunc.master.slave_state[slave].event_eq; u32 in_modifier = vhcr->in_modifier; - u32 eqn = in_modifier & 0x1FF; + u32 eqn = in_modifier & 0x3FF; u64 in_param = vhcr->in_param; int err = 0; int i; -- cgit v1.2.3 From 80cb0021163cb55b14c7c054073f89d63a2e1e40 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 21 Mar 2013 05:55:52 +0000 Subject: net/mlx4_core: Fix wrong order of flow steering resources removal On the resource tracker cleanup flow, the DMFS rules must be deleted before we destroy the QPs, else the HW may attempt doing packet steering to non existent QPs. Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 2995687f1aee..0d1d9679179c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -3806,6 +3806,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); /*VLAN*/ rem_slave_macs(dev, slave); + rem_slave_fs_rule(dev, slave); rem_slave_qps(dev, slave); rem_slave_srqs(dev, slave); rem_slave_cqs(dev, slave); @@ -3814,6 +3815,5 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) rem_slave_mtts(dev, slave); rem_slave_counters(dev, slave); rem_slave_xrcdns(dev, slave); - rem_slave_fs_rule(dev, slave); mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); } -- cgit v1.2.3 From 6efb5fac4d6b617972ab5a10bf67e0eba2c2d212 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 21 Mar 2013 05:55:53 +0000 Subject: net/mlx4_en: Remove ethtool flow steering rules before releasing QPs Fix the ethtool flow steering rules cleanup to be carried out before releasing the RX QPs. Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 995d4b6d5c1e..f278b10ef714 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1637,6 +1637,17 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) /* Flush multicast filter */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); + /* Remove flow steering rules for the port*/ + if (mdev->dev->caps.steering_mode == + MLX4_STEERING_MODE_DEVICE_MANAGED) { + ASSERT_RTNL(); + list_for_each_entry_safe(flow, tmp_flow, + &priv->ethtool_list, list) { + mlx4_flow_detach(mdev->dev, flow->id); + list_del(&flow->list); + } + } + mlx4_en_destroy_drop_qp(priv); /* Free TX Rings */ @@ -1657,17 +1668,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN)) mdev->mac_removed[priv->port] = 1; - /* Remove flow steering rules for the port*/ - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - ASSERT_RTNL(); - list_for_each_entry_safe(flow, tmp_flow, - &priv->ethtool_list, list) { - mlx4_flow_detach(mdev->dev, flow->id); - list_del(&flow->list); - } - } - /* Free RX Rings */ for (i = 0; i < priv->rx_ring_num; i++) { mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); -- cgit v1.2.3 From 1e3f7b324e46b772dec1bb6dd96ae745fc085401 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 21 Mar 2013 05:55:54 +0000 Subject: net/mlx4_core: Always use 64 bit resource ID when doing lookup One of the resource tracker code paths was wrongly using int and not u64 for resource tracking IDs, fix it. Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 0d1d9679179c..b0ccdb55ca46 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -355,7 +355,7 @@ static int mpt_mask(struct mlx4_dev *dev) return dev->caps.num_mpts - 1; } -static void *find_res(struct mlx4_dev *dev, int res_id, +static void *find_res(struct mlx4_dev *dev, u64 res_id, enum mlx4_resource type) { struct mlx4_priv *priv = mlx4_priv(dev); -- cgit v1.2.3 From 2c473ae7e5826c108e52f4a9d75425fd4c6f9ed1 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 21 Mar 2013 05:55:55 +0000 Subject: net/mlx4_core: Disallow releasing VF QPs which have steering rules VF QPs must not be released when they have steering rules attached to them. For that end, introduce a reference count field to the QP object in the SRIOV resource tracker which is incremented/decremented when steering rules are attached/detached to it. QPs can be released by VF only when their ref count is zero. Signed-off-by: Hadar Hen Zion Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/resource_tracker.c | 41 +++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index b0ccdb55ca46..1391b52f443a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -99,6 +99,7 @@ struct res_qp { struct list_head mcg_list; spinlock_t mcg_spl; int local_qpn; + atomic_t ref_count; }; enum res_mtt_states { @@ -197,6 +198,7 @@ enum res_fs_rule_states { struct res_fs_rule { struct res_common com; + int qpn; }; static void *res_tracker_lookup(struct rb_root *root, u64 res_id) @@ -447,6 +449,7 @@ static struct res_common *alloc_qp_tr(int id) ret->local_qpn = id; INIT_LIST_HEAD(&ret->mcg_list); spin_lock_init(&ret->mcg_spl); + atomic_set(&ret->ref_count, 0); return &ret->com; } @@ -554,7 +557,7 @@ static struct res_common *alloc_xrcdn_tr(int id) return &ret->com; } -static struct res_common *alloc_fs_rule_tr(u64 id) +static struct res_common *alloc_fs_rule_tr(u64 id, int qpn) { struct res_fs_rule *ret; @@ -564,7 +567,7 @@ static struct res_common *alloc_fs_rule_tr(u64 id) ret->com.res_id = id; ret->com.state = RES_FS_RULE_ALLOCATED; - + ret->qpn = qpn; return &ret->com; } @@ -602,7 +605,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, ret = alloc_xrcdn_tr(id); break; case RES_FS_RULE: - ret = alloc_fs_rule_tr(id); + ret = alloc_fs_rule_tr(id, extra); break; default: return NULL; @@ -671,10 +674,14 @@ undo: static int remove_qp_ok(struct res_qp *res) { - if (res->com.state == RES_QP_BUSY) + if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || + !list_empty(&res->mcg_list)) { + pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", + res->com.state, atomic_read(&res->ref_count)); return -EBUSY; - else if (res->com.state != RES_QP_RESERVED) + } else if (res->com.state != RES_QP_RESERVED) { return -EPERM; + } return 0; } @@ -3124,6 +3131,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; int err; int qpn; + struct res_qp *rqp; struct mlx4_net_trans_rule_hw_ctrl *ctrl; struct _rule_hw *rule_header; int header_id; @@ -3134,7 +3142,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, NULL); + err = get_res(dev, slave, qpn, RES_QP, &rqp); if (err) { pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); return err; @@ -3175,14 +3183,16 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, if (err) goto err_put; - err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0); + err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); if (err) { mlx4_err(dev, "Fail to add flow steering resources.\n "); /* detach rule*/ mlx4_cmd(dev, vhcr->out_param, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); + goto err_put; } + atomic_inc(&rqp->ref_count); err_put: put_res(dev, slave, qpn, RES_QP); return err; @@ -3195,20 +3205,35 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int err; + struct res_qp *rqp; + struct res_fs_rule *rrule; if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) return -EOPNOTSUPP; + err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); + if (err) + return err; + /* Release the rule form busy state before removal */ + put_res(dev, slave, vhcr->in_param, RES_FS_RULE); + err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); + if (err) + return err; + err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0); if (err) { mlx4_err(dev, "Fail to remove flow steering resources.\n "); - return err; + goto out; } err = mlx4_cmd(dev, vhcr->in_param, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); + if (!err) + atomic_dec(&rqp->ref_count); +out: + put_res(dev, slave, rrule->qpn, RES_QP); return err; } -- cgit v1.2.3 From 3cf956eebe54cdb7cf1701642085507f0354e56a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Mar 2013 10:12:10 +0100 Subject: ASoC: wm8994: Support constraining the maximum number of channels clocked Some systems use the audio CODEC to clock a DAI with multiple data lines in parallel, meaning that bit clocks are only required for a smaller number of channels than data is sent for. In some cases providing the extra bit clocks can take the other devices on the audio bus out of spec. Support such systems by allowing a maximum number of channels to be specified. Signed-off-by: Mark Brown --- include/linux/mfd/wm8994/pdata.h | 8 ++++++++ sound/soc/codecs/wm8994.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 8e21a094836d..68e776594889 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -17,6 +17,7 @@ #define WM8994_NUM_LDO 2 #define WM8994_NUM_GPIO 11 +#define WM8994_NUM_AIF 3 struct wm8994_ldo_pdata { /** GPIOs to enable regulator, 0 or less if not available */ @@ -215,6 +216,13 @@ struct wm8994_pdata { * system. */ bool spkmode_pu; + + /** + * Maximum number of channels clocks will be generated for, + * useful for systems where and I2S bus with multiple data + * lines is mastered. + */ + int max_channels_clocked[WM8994_NUM_AIF]; }; #endif diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c9bd445c4976..318ea64b9800 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2656,6 +2656,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; int aif1_reg; int aif2_reg; int bclk_reg; @@ -2723,7 +2725,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, } wm8994->channels[id] = params_channels(params); - switch (params_channels(params)) { + if (pdata->max_channels_clocked[id] && + wm8994->channels[id] > pdata->max_channels_clocked[id]) { + dev_dbg(dai->dev, "Constraining channels to %d from %d\n", + pdata->max_channels_clocked[id], wm8994->channels[id]); + wm8994->channels[id] = pdata->max_channels_clocked[id]; + } + + switch (wm8994->channels[id]) { case 1: case 2: bclk_rate *= 2; @@ -2745,7 +2754,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n", dai->id, wm8994->aifclk[id], bclk_rate); - if (params_channels(params) == 1 && + if (wm8994->channels[id] == 1 && (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18) aif2 |= WM8994_AIF1_MONO; -- cgit v1.2.3 From ae5fc98728c8bbbd6d7cab0b9781671fc4419c1b Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 21 Mar 2013 20:33:46 +0400 Subject: net: fix *_DIAG_MAX constants Follow the common pattern and define *_DIAG_MAX like: [...] __XXX_DIAG_MAX, }; Because everyone is used to do: struct nlattr *attrs[XXX_DIAG_MAX+1]; nla_parse([...], XXX_DIAG_MAX, [...] Reported-by: Thomas Graf Cc: "David S. Miller" Cc: Pavel Emelyanov Cc: Eric Dumazet Cc: "Paul E. McKenney" Cc: David Howells Signed-off-by: Andrey Vagin Signed-off-by: David S. Miller --- include/uapi/linux/packet_diag.h | 4 +++- include/uapi/linux/unix_diag.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/packet_diag.h b/include/uapi/linux/packet_diag.h index 93f5fa94a431..afafd703ad92 100644 --- a/include/uapi/linux/packet_diag.h +++ b/include/uapi/linux/packet_diag.h @@ -33,9 +33,11 @@ enum { PACKET_DIAG_TX_RING, PACKET_DIAG_FANOUT, - PACKET_DIAG_MAX, + __PACKET_DIAG_MAX, }; +#define PACKET_DIAG_MAX (__PACKET_DIAG_MAX - 1) + struct packet_diag_info { __u32 pdi_index; __u32 pdi_version; diff --git a/include/uapi/linux/unix_diag.h b/include/uapi/linux/unix_diag.h index b8a24941db21..b9e2a6a7446f 100644 --- a/include/uapi/linux/unix_diag.h +++ b/include/uapi/linux/unix_diag.h @@ -39,9 +39,11 @@ enum { UNIX_DIAG_MEMINFO, UNIX_DIAG_SHUTDOWN, - UNIX_DIAG_MAX, + __UNIX_DIAG_MAX, }; +#define UNIX_DIAG_MAX (__UNIX_DIAG_MAX - 1) + struct unix_diag_vfs { __u32 udiag_vfs_ino; __u32 udiag_vfs_dev; -- cgit v1.2.3 From 06ae43f34bcc07a0b6be8bf78a1c895bcd12c839 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 20 Mar 2013 13:19:30 -0400 Subject: Don't bother with redoing rw_verify_area() from default_file_splice_from() default_file_splice_from() ends up calling vfs_write() (via very convoluted callchain). It's an overkill, since we already have done rw_verify_area() in the caller by the time we call vfs_write() we are under set_fs(KERNEL_DS), so access_ok() is also pointless. Add a new helper (__kernel_write()), use it instead of kernel_write() in there. Signed-off-by: Al Viro --- fs/internal.h | 5 +++++ fs/read_write.c | 25 +++++++++++++++++++++++++ fs/splice.c | 4 +++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/fs/internal.h b/fs/internal.h index 507141fceb99..4be78237d896 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool); * dcache.c */ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); + +/* + * read_write.c + */ +extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); diff --git a/fs/read_write.c b/fs/read_write.c index a698eff457fb..f7b5a23b804b 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -17,6 +17,7 @@ #include #include #include "read_write.h" +#include "internal.h" #include #include @@ -417,6 +418,30 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof EXPORT_SYMBOL(do_sync_write); +ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + const char __user *p; + ssize_t ret; + + old_fs = get_fs(); + set_fs(get_ds()); + p = (__force const char __user *)buf; + if (count > MAX_RW_COUNT) + count = MAX_RW_COUNT; + if (file->f_op->write) + ret = file->f_op->write(file, p, count, pos); + else + ret = do_sync_write(file, p, count, pos); + set_fs(old_fs); + if (ret > 0) { + fsnotify_modify(file); + add_wchar(current, ret); + } + inc_syscw(current); + return ret; +} + ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { ssize_t ret; diff --git a/fs/splice.c b/fs/splice.c index 718bd0056384..29e394e49ddd 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -31,6 +31,7 @@ #include #include #include +#include "internal.h" /* * Attempt to steal a page from a pipe buffer. This should perhaps go into @@ -1048,9 +1049,10 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, { int ret; void *data; + loff_t tmp = sd->pos; data = buf->ops->map(pipe, buf, 0); - ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); + ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp); buf->ops->unmap(pipe, buf, data); return ret; -- cgit v1.2.3 From 48a23fac5eb0030a2d578ee2bde21b6e035b3d57 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Tue, 19 Mar 2013 20:07:42 +0100 Subject: pinctrl: mvebu: fix checking for SoC specific controls This patch fixes a minor bug (probably due to a typo) while checking the SoC specific controls in mvebu_pinctrl_probe(). Acked-by: Sebastian Hesselbarth Signed-off-by: Simon Guinot Signed-off-by: Linus Walleij --- drivers/pinctrl/mvebu/pinctrl-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index c689c04a4f52..2d2f0a43d36b 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -620,7 +620,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev) /* special soc specific control */ if (ctrl->mpp_get || ctrl->mpp_set) { - if (!ctrl->name || !ctrl->mpp_set || !ctrl->mpp_set) { + if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) { dev_err(&pdev->dev, "wrong soc control info\n"); return -EINVAL; } -- cgit v1.2.3 From 4f1b07581613bf076b0dacdd9a3fb290d3caa227 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Jan 2013 15:38:48 +0000 Subject: mfd: wm5102: Add additional speaker control registers Signed-off-by: Mark Brown --- drivers/mfd/wm5102-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 8a6ce8c12505..7d01069c09db 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -1169,6 +1169,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_NOISE_GATE_CONTROL: case ARIZONA_PDM_SPK1_CTRL_1: case ARIZONA_PDM_SPK1_CTRL_2: + case ARIZONA_SPK_CTRL_2: + case ARIZONA_SPK_CTRL_3: case ARIZONA_DAC_COMP_1: case ARIZONA_DAC_COMP_2: case ARIZONA_DAC_COMP_3: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index a61ce90ecd3f..a47fd358016f 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -217,6 +217,8 @@ #define ARIZONA_PDM_SPK1_CTRL_2 0x491 #define ARIZONA_PDM_SPK2_CTRL_1 0x492 #define ARIZONA_PDM_SPK2_CTRL_2 0x493 +#define ARIZONA_SPK_CTRL_2 0x4B5 +#define ARIZONA_SPK_CTRL_3 0x4B6 #define ARIZONA_DAC_COMP_1 0x4DC #define ARIZONA_DAC_COMP_2 0x4DD #define ARIZONA_DAC_COMP_3 0x4DE -- cgit v1.2.3 From 56447e1324009d7e3cec40e3cc2987843b59a00f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Jan 2013 14:45:58 +0000 Subject: ASoC: arizona: Factor out speaker widgets from CODEC drivers Some system designs have been identified which repurpose portions of the speaker driver circuits for other functions which will require that they not be managed using DAPM. Prepare for this by factoring out the creation of the speaker widgets into the core driver, the widgets will be replaced by dummy ones when the additional functions are enabled. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 5 +++ sound/soc/codecs/wm5102.c | 52 ++--------------------------- sound/soc/codecs/wm5110.c | 6 ---- 4 files changed, 89 insertions(+), 56 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 2b0803ec8234..009810b8c667 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,87 @@ #define arizona_aif_dbg(_dai, fmt, ...) \ dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) +static int arizona_spk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = w->codec; + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + bool manual_ena = false; + + switch (arizona->type) { + case WM5102: + switch (arizona->rev) { + case 0: + break; + default: + manual_ena = true; + break; + } + default: + break; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!priv->spk_ena && manual_ena) { + snd_soc_write(codec, 0x4f5, 0x25a); + priv->spk_ena_pending = true; + } + break; + case SND_SOC_DAPM_POST_PMU: + if (priv->spk_ena_pending) { + msleep(75); + snd_soc_write(codec, 0x4f5, 0xda); + priv->spk_ena_pending = false; + priv->spk_ena++; + } + break; + case SND_SOC_DAPM_PRE_PMD: + if (manual_ena) { + priv->spk_ena--; + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x25a); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (manual_ena) { + if (!priv->spk_ena) + snd_soc_write(codec, 0x4f5, 0x0da); + } + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget arizona_spkl = + SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +static const struct snd_soc_dapm_widget arizona_spkr = + SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + +int arizona_init_spk(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); + if (ret != 0) + return ret; + + ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1); + if (ret != 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 572f11bc90b4..9399940f700d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -76,6 +76,9 @@ struct arizona_priv { int num_inputs; unsigned int in_pending; + + unsigned int spk_ena:2; + unsigned int spk_ena_pending:1; }; #define ARIZONA_NUM_MIXER_INPUTS 99 @@ -228,6 +231,8 @@ extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); +extern int arizona_init_spk(struct snd_soc_codec *codec); + extern int arizona_init_dai(struct arizona_priv *priv, int dai); int arizona_set_output_mode(struct snd_soc_codec *codec, int output, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 44d4c69d25e5..97757bc5fd0e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -36,9 +36,6 @@ struct wm5102_priv { struct arizona_priv core; struct arizona_fll fll[2]; - - unsigned int spk_ena:2; - unsigned int spk_ena_pending:1; }; static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); @@ -817,47 +814,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), }; -static int wm5102_spk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = w->codec; - struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); - - if (arizona->rev < 1) - return 0; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (!wm5102->spk_ena) { - snd_soc_write(codec, 0x4f5, 0x25a); - wm5102->spk_ena_pending = true; - } - break; - case SND_SOC_DAPM_POST_PMU: - if (wm5102->spk_ena_pending) { - msleep(75); - snd_soc_write(codec, 0x4f5, 0xda); - wm5102->spk_ena_pending = false; - wm5102->spk_ena++; - } - break; - case SND_SOC_DAPM_PRE_PMD: - wm5102->spk_ena--; - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x25a); - break; - case SND_SOC_DAPM_POST_PMD: - if (!wm5102->spk_ena) - snd_soc_write(codec, 0x4f5, 0x0da); - break; - } - - return 0; -} - - ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); @@ -1141,12 +1097,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -1586,6 +1536,8 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; + arizona_init_spk(codec); + snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); priv->core.arizona->dapm = &codec->dapm; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index a64d3b8bc3b4..b6329c8c19df 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -577,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -- cgit v1.2.3 From 899817e27a58038546b53bc42eeaa4aae5a886cb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 13 Mar 2013 12:32:10 +0000 Subject: ASoC: arizona: Log thermal events Help with debuggability. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 009810b8c667..895ddf007de2 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -122,6 +122,42 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, return 0; } +static irqreturn_t arizona_thermal_warn(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) { + dev_crit(arizona->dev, "Thermal warning\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t arizona_thermal_shutdown(int irq, void *data) +{ + struct arizona *arizona = data; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3, + &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read thermal status: %d\n", + ret); + } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, "Thermal shutdown\n"); + } + + return IRQ_HANDLED; +} + static const struct snd_soc_dapm_widget arizona_spkl = SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, @@ -134,6 +170,8 @@ static const struct snd_soc_dapm_widget arizona_spkr = int arizona_init_spk(struct snd_soc_codec *codec) { + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; int ret; ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1); @@ -144,6 +182,22 @@ int arizona_init_spk(struct snd_soc_codec *codec) if (ret != 0) return ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, + "Thermal warning", arizona_thermal_warn, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal warning IRQ: %d\n", + ret); + + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN, + "Thermal shutdown", arizona_thermal_shutdown, + arizona); + if (ret != 0) + dev_err(arizona->dev, + "Failed to get thermal shutdown IRQ: %d\n", + ret); + return 0; } EXPORT_SYMBOL_GPL(arizona_init_spk); -- cgit v1.2.3 From f4a76e7cc6d1c402e990e2111fb94afb305fb974 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 13 Mar 2013 12:22:39 +0000 Subject: ASoC: arizona: Suppress speaker enable if thermal shutdown is flagged Ensure that the device state does not diverge from the state we have set in the register map in order to make the behaviour clearer. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 895ddf007de2..6c773804ffe0 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -75,6 +75,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, struct arizona *arizona = dev_get_drvdata(codec->dev->parent); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); bool manual_ena = false; + int val; switch (arizona->type) { case WM5102: @@ -97,6 +98,16 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMU: + val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); + if (val & ARIZONA_SPK_SHUTDOWN_STS) { + dev_crit(arizona->dev, + "Speaker not enabled due to temperature\n"); + return -EBUSY; + } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 1 << w->shift); + if (priv->spk_ena_pending) { msleep(75); snd_soc_write(codec, 0x4f5, 0xda); @@ -110,6 +121,9 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, if (!priv->spk_ena) snd_soc_write(codec, 0x4f5, 0x25a); } + + snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1, + 1 << w->shift, 0); break; case SND_SOC_DAPM_POST_PMD: if (manual_ena) { @@ -153,18 +167,26 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) ret); } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { dev_crit(arizona->dev, "Thermal shutdown\n"); + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT4L_ENA | + ARIZONA_OUT4R_ENA, 0); + if (ret != 0) + dev_crit(arizona->dev, + "Failed to disable speaker outputs: %d\n", + ret); } return IRQ_HANDLED; } static const struct snd_soc_dapm_widget arizona_spkl = - SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, + SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); static const struct snd_soc_dapm_widget arizona_spkr = - SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, + SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM, ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); -- cgit v1.2.3 From dc91428a6152b2c8428a39a27ab9b5e429848f55 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 18 Feb 2013 19:09:23 +0000 Subject: ASoC: arizona: Basic support for ISRC rate selection Since ASoC does not yet really have the framework features needed to support propagating sample rates through the device well yet implement basic support for the ISRCs equivalent to that we currently have for the ASRCs. The user can opt for 8kHz or 16kHz as the rate for the DSP blocks in addition to the main audio rate, these being the primary use cases. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 27 +++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 6 ++++++ sound/soc/codecs/wm5102.c | 11 ++++++++++- sound/soc/codecs/wm_adsp.c | 24 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6c773804ffe0..26e1579c36cb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -433,6 +433,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values); const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); EXPORT_SYMBOL_GPL(arizona_mixer_tlv); +const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { + "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate", +}; +EXPORT_SYMBOL_GPL(arizona_rate_text); + +const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { + 0, 1, 2, 8, +}; +EXPORT_SYMBOL_GPL(arizona_rate_val); + + +const struct soc_enum arizona_isrc_fsl[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2, + ARIZONA_ISRC1_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2, + ARIZONA_ISRC2_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2, + ARIZONA_ISRC3_FSL_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; +EXPORT_SYMBOL_GPL(arizona_isrc_fsl); + static const char *arizona_vol_ramp_text[] = { "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", "15ms/6dB", "30ms/6dB", diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9399940f700d..a754a1c0217f 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -180,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_ROUTES(name, name "L"), \ ARIZONA_MIXER_ROUTES(name, name "R") +#define ARIZONA_RATE_ENUM_SIZE 4 +extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; +extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; + +extern const struct soc_enum arizona_isrc_fsl[]; + extern const struct soc_enum arizona_in_vi_ramp; extern const struct soc_enum arizona_in_vd_ramp; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 97757bc5fd0e..a0084b1febdb 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -731,6 +731,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), + ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -1532,7 +1535,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1); + ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); if (ret != 0) return ret; @@ -1624,6 +1627,12 @@ static int wm5102_probe(struct platform_device *pdev) ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, &wm5102->fll[1]); + /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, + ARIZONA_SAMPLE_RATE_2_MASK, 0x11); + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, + ARIZONA_SAMPLE_RATE_3_MASK, 0x12); + for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++) arizona_init_dai(&wm5102->core, i); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f3f7e75f8628..3a481fd1bf9a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -31,6 +31,7 @@ #include +#include "arizona.h" #include "wm_adsp.h" #define adsp_crit(_dsp, fmt, ...) \ @@ -246,15 +247,38 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; +static const struct soc_enum wm_adsp_rate_enum[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1, + ARIZONA_DSP1_RATE_SHIFT, 0xf, + ARIZONA_RATE_ENUM_SIZE, + arizona_rate_text, arizona_rate_val), +}; + const struct snd_kcontrol_new wm_adsp_fw_controls[] = { SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP1 Rate", wm_adsp_rate_enum[0]), SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP2 Rate", wm_adsp_rate_enum[1]), SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP3 Rate", wm_adsp_rate_enum[2]), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP4 Rate", wm_adsp_rate_enum[3]), }; EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); -- cgit v1.2.3 From 740924a267e85de09707ea158bbf594b4d8bae01 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Thu, 21 Mar 2013 12:21:47 +0100 Subject: pinmux: forbid mux_usecount to be set at UINT_MAX If pin_free is called on a pin already freed, mux_usecount is set to UINT_MAX which is really a bad idea. This will issue a warning, so that we can correct the code responsible for the double free. Signed-off-by: Richard Genoud Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 1a00658b3ea0..bd83c8b01cd1 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -194,6 +194,11 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, } if (!gpio_range) { + /* + * A pin should not be freed more times than allocated. + */ + if (WARN_ON(!desc->mux_usecount)) + return NULL; desc->mux_usecount--; if (desc->mux_usecount) return NULL; -- cgit v1.2.3 From bc8ce4afd7ee7e1421c935d24b1f879f82afdd4e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 20 Mar 2013 17:02:02 -0600 Subject: regmap: don't corrupt work buffer in _regmap_raw_write() _regmap_raw_write() contains code to call regcache_write() to write values to the cache. That code calls memcpy() to copy the value data to the start of the work_buf. However, at least when _regmap_raw_write() is called from _regmap_bus_raw_write(), the value data is in the work_buf, and this memcpy() operation may over-write part of that value data, depending on the value of reg_bytes + pad_bytes. At least when using reg_bytes==1 and pad_bytes==0, corruption of the value data does occur. To solve this, remove the memcpy() operation, and modify the subsequent .parse_val() call to parse the original value buffer directly. At least in the case of 8-bit register address and 16-bit values, and writes of single registers at a time, this memcpy-then-parse combination used to cancel each-other out; for a work-buffer containing xx 89 03, the memcpy changed it to 89 03 03, and the parse_val changed it back to 89 89 03, thus leaving the value uncorrupted. This appears completely accidental though. Since commit 8a819ff "regmap: core: Split out in place value parsing", .parse_val only returns the parsed value, and does not modify the buffer, and hence does not (accidentally) undo the corruption caused by memcpy(). This caused bogus values to get written to HW, thus preventing e.g. audio playback on systems with a WM8903 CODEC. This patch fixes that. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 3d2367501fd0..89a920510e1d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -943,8 +943,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, unsigned int ival; int val_bytes = map->format.val_bytes; for (i = 0; i < val_len / val_bytes; i++) { - memcpy(map->work_buf, val + (i * val_bytes), val_bytes); - ival = map->format.parse_val(map->work_buf); + ival = map->format.parse_val(val + (i * val_bytes)); ret = regcache_write(map, reg + (i * map->reg_stride), ival); if (ret) { -- cgit v1.2.3 From d3725761ee3d4813c6071ea1d952de1094d8b68f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 29 Jan 2013 23:17:12 +0800 Subject: ASoC: wm8994: Restore AIFnCLK after reducing it for low clock rates This helps to ensure a smooth startup when we restore. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8994.h | 1 + 2 files changed, 33 insertions(+) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 318ea64b9800..1c02a47910e4 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2268,10 +2268,26 @@ out: */ if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + + wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE) + & WM8994_AIF1CLK_RATE_MASK; + wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE) + & WM8994_AIF1CLK_RATE_MASK; + snd_soc_update_bits(codec, WM8994_AIF1_RATE, WM8994_AIF1CLK_RATE_MASK, 0x1); snd_soc_update_bits(codec, WM8994_AIF2_RATE, WM8994_AIF2CLK_RATE_MASK, 0x1); + } else if (wm8994->aifdiv[0]) { + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, + wm8994->aifdiv[0]); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, + wm8994->aifdiv[1]); + + wm8994->aifdiv[0] = 0; + wm8994->aifdiv[1] = 0; } return 0; @@ -2368,10 +2384,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, */ if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) { dev_dbg(codec->dev, "Configuring AIFs for 128fs\n"); + + wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE) + & WM8994_AIF1CLK_RATE_MASK; + wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE) + & WM8994_AIF1CLK_RATE_MASK; + snd_soc_update_bits(codec, WM8994_AIF1_RATE, WM8994_AIF1CLK_RATE_MASK, 0x1); snd_soc_update_bits(codec, WM8994_AIF2_RATE, WM8994_AIF2CLK_RATE_MASK, 0x1); + } else if (wm8994->aifdiv[0]) { + snd_soc_update_bits(codec, WM8994_AIF1_RATE, + WM8994_AIF1CLK_RATE_MASK, + wm8994->aifdiv[0]); + snd_soc_update_bits(codec, WM8994_AIF2_RATE, + WM8994_AIF2CLK_RATE_MASK, + wm8994->aifdiv[1]); + + wm8994->aifdiv[0] = 0; + wm8994->aifdiv[1] = 0; } return 0; diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 45f192702024..928e2c256450 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -79,6 +79,7 @@ struct wm8994_priv { int sysclk_rate[2]; int mclk[2]; int aifclk[2]; + int aifdiv[2]; int channels[2]; struct wm8994_fll_config fll[2], fll_suspend[2]; struct completion fll_locked[2]; -- cgit v1.2.3 From 4cec1893d8fe01ef6adc89a135a804acd2989a48 Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Thu, 21 Feb 2013 07:54:18 -0300 Subject: [media] fimc-lite: Initialize 'step' field in fimc_lite_ctrl structure v4l2_ctrl_new() uses check_range() for control range checking. This function expects 'step' value for V4L2_CTRL_TYPE_BOOLEAN type control. If 'step' value doesn't match to '1', it returns -ERANGE error. This patch adds the default .step value to 1. Signed-off-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-lite.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index bfc4206935c8..bbc35de7db27 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -1408,6 +1408,7 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = { .id = V4L2_CTRL_CLASS_USER | 0x1001, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Test Pattern 640x480", + .step = 1, }; static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) -- cgit v1.2.3 From 6a5360966ac44905ecb840dd6c9d736072145df2 Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Thu, 21 Feb 2013 07:54:17 -0300 Subject: [media] fimc-lite: Fix the variable type to avoid possible crash Changing the variable type to 'int' from 'unsigned int'. Driver logic expects the variable type to be 'int'. Signed-off-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-lite-reg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c index f0af0754a7b4..ac9663ce2a49 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c @@ -128,10 +128,10 @@ static const u32 src_pixfmt_map[8][3] = { void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) { enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; - unsigned int i = ARRAY_SIZE(src_pixfmt_map); + int i = ARRAY_SIZE(src_pixfmt_map); u32 cfg; - while (i-- >= 0) { + while (--i >= 0) { if (src_pixfmt_map[i][0] == pixelcode) break; } @@ -224,9 +224,9 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, }; u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); - unsigned int i = ARRAY_SIZE(pixcode); + int i = ARRAY_SIZE(pixcode); - while (i-- >= 0) + while (--i >= 0) if (pixcode[i][0] == dev->fmt->mbus_code) break; cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; -- cgit v1.2.3 From 5d83790be7c88a5ea99ab32ca196d99cf4d177a4 Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Wed, 6 Feb 2013 01:46:18 -0300 Subject: [media] exynos-gsc: send valid m2m ctx to gsc_m2m_job_finish gsc_m2m_job_finish() has to be called with the m2m context for the necessary cleanup while resume. But currently gsc_m2m_job_finish() always passes m2m context as NULL. This patch preserves the context before making it null, for necessary cleanup. Use gsc_m2m_opened() instead gsc_m2m_active() in gsc_resume(). Signed-off-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 82d9f6ac12f3..33b5ffc8d66d 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1054,16 +1054,18 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc) static int gsc_m2m_resume(struct gsc_dev *gsc) { + struct gsc_ctx *ctx; unsigned long flags; spin_lock_irqsave(&gsc->slock, flags); /* Clear for full H/W setup in first run after resume */ + ctx = gsc->m2m.ctx; gsc->m2m.ctx = NULL; spin_unlock_irqrestore(&gsc->slock, flags); if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) - gsc_m2m_job_finish(gsc->m2m.ctx, - VB2_BUF_STATE_ERROR); + gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + return 0; } @@ -1204,7 +1206,7 @@ static int gsc_resume(struct device *dev) /* Do not resume if the device was idle before system suspend */ spin_lock_irqsave(&gsc->slock, flags); if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) || - !gsc_m2m_active(gsc)) { + !gsc_m2m_opened(gsc)) { spin_unlock_irqrestore(&gsc->slock, flags); return 0; } -- cgit v1.2.3 From e34a89b39719dd1eb08e0b23c907e98b103078b4 Mon Sep 17 00:00:00 2001 From: Shaik Ameer Basha Date: Wed, 6 Feb 2013 01:47:10 -0300 Subject: [media] s5p-fimc: send valid m2m ctx to fimc_m2m_job_finish fimc_m2m_job_finish() has to be called with the m2m context for the necessary cleanup while resume. But currently fimc_m2m_job_finish() always passes m2m context as NULL. This patch preserves the context before making it null, for necessary cleanup. Signed-off-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index e3916bde45cf..0f513dd19f86 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -850,16 +850,18 @@ static int fimc_m2m_suspend(struct fimc_dev *fimc) static int fimc_m2m_resume(struct fimc_dev *fimc) { + struct fimc_ctx *ctx; unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); /* Clear for full H/W setup in first run after resume */ + ctx = fimc->m2m.ctx; fimc->m2m.ctx = NULL; spin_unlock_irqrestore(&fimc->slock, flags); if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state)) - fimc_m2m_job_finish(fimc->m2m.ctx, - VB2_BUF_STATE_ERROR); + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + return 0; } -- cgit v1.2.3 From 90c0ae50097bba165022ddf0a592aa4001e23aaa Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Tue, 26 Feb 2013 18:02:11 -0300 Subject: [media] s5p-mfc: Fix frame skip bug The issue was seen in VP8 decoding where the last frame was skipped by the driver. This patch gets the correct frame_type value to fix this bug. Signed-off-by: Arun Kumar K Signed-off-by: Arun Mankuzhi Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e84703c314ce..1cb6d57987c6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -276,7 +276,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) unsigned int frame_type; dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); - frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx); /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { -- cgit v1.2.3 From 053e09f319c25fb9c698ad56b9b65058939ec6ef Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 6 Mar 2013 09:15:57 -0300 Subject: [media] s5p-mfc: Fix encoder control 15 issue mfc-encoder is not working in the latest kernel giving the erorr "Adding control (15) failed". Adding the missing step parameter in this control to fix the issue. Signed-off-by: Arun Kumar K Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 2356fd52a169..4f6b553c4b2d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -232,6 +232,7 @@ static struct mfc_control controls[] = { .minimum = 0, .maximum = 1, .default_value = 0, + .step = 1, .menu_skip_mask = 0, }, { -- cgit v1.2.3 From 8c6ecdd7ce11e737eeffbd78fd6a9d4c47d0b26d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 5 Feb 2013 15:43:08 -0300 Subject: [media] s5p-fimc: Do not attempt to disable not enabled media pipeline This fixes following warnings when all links are being disconnected: [ 20.080000] WARNING: at drivers/media/platform/s5p-fimc/fimc-mdevice.c:1269 __fimc_md_set_camclk+0x208/0x20c() [ 20.090000] Modules linked in: [ 20.095000] [] (unwind_backtrace+0x0/0x13c) from [] (warn_slowpath_common+0x54/0x64) [ 20.105000] [] (warn_slowpath_common+0x54/0x64) from [] (warn_slowpath_null+0x1c/0x24) [ 20.115000] [] (warn_slowpath_null+0x1c/0x24) from [] (__fimc_md_set_camclk+0x208/0x20c) [ 20.125000] [] (__fimc_md_set_camclk+0x208/0x20c) from [] (__fimc_pipeline_close+0x38/0x48) [ 20.135000] [] (__fimc_pipeline_close+0x38/0x48) from [] (fimc_md_link_notify+0x10c/0x198) [ 20.145000] [] (fimc_md_link_notify+0x10c/0x198) from [] (__media_entity_setup_link+0x1c0/0x1e8) [ 20.155000] [] (__media_entity_setup_link+0x1c0/0x1e8) from [] (media_device_ioctl+0x2c0/0x41c) [ 20.165000] [] (media_device_ioctl+0x2c0/0x41c) from [] (media_ioctl+0x30/0x34) [ 20.175000] [] (media_ioctl+0x30/0x34) from [] (do_vfs_ioctl+0x84/0x5e8) [ 20.185000] [] (do_vfs_ioctl+0x84/0x5e8) from [] (sys_ioctl+0x3c/0x60) [ 20.190000] [] (sys_ioctl+0x3c/0x60) from [] (ret_fast_syscall+0x0/0x30) Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 39 +++++++++++++------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index a17fcb2d5d41..cd38d708ab58 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -827,7 +827,7 @@ static int fimc_md_link_notify(struct media_pad *source, struct fimc_pipeline *pipeline; struct v4l2_subdev *sd; struct mutex *lock; - int ret = 0; + int i, ret = 0; int ref_count; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) @@ -854,29 +854,28 @@ static int fimc_md_link_notify(struct media_pad *source, return 0; } + mutex_lock(lock); + ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; + if (!(flags & MEDIA_LNK_FL_ENABLED)) { - int i; - mutex_lock(lock); - ret = __fimc_pipeline_close(pipeline); + if (ref_count > 0) { + ret = __fimc_pipeline_close(pipeline); + if (!ret && fimc) + fimc_ctrls_delete(fimc->vid_cap.ctx); + } for (i = 0; i < IDX_MAX; i++) pipeline->subdevs[i] = NULL; - if (fimc) - fimc_ctrls_delete(fimc->vid_cap.ctx); - mutex_unlock(lock); - return ret; + } else if (ref_count > 0) { + /* + * Link activation. Enable power of pipeline elements only if + * the pipeline is already in use, i.e. its video node is open. + * Recreate the controls destroyed during the link deactivation. + */ + ret = __fimc_pipeline_open(pipeline, + source->entity, true); + if (!ret && fimc) + ret = fimc_capture_ctrls_create(fimc); } - /* - * Link activation. Enable power of pipeline elements only if the - * pipeline is already in use, i.e. its video node is opened. - * Recreate the controls destroyed during the link deactivation. - */ - mutex_lock(lock); - - ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; - if (ref_count > 0) - ret = __fimc_pipeline_open(pipeline, source->entity, true); - if (!ret && fimc) - ret = fimc_capture_ctrls_create(fimc); mutex_unlock(lock); return ret ? -EPIPE : ret; -- cgit v1.2.3 From 6ba4d05e84eeb450011f7f3514ec8556d3b46743 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 27 Feb 2013 08:21:07 -0300 Subject: [media] m5mols: Fix bug in stream on handler Due to improper condition check streaming start for some pixel formats was prevent and the s_stream just reatuned -EINVAL. This fixes regression introduced in commit 5565a2ad47cdd8e697 [media] m5mols: Protect driver data with a mutex. Signed-off-by: Andrzej Hajda Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/m5mols/m5mols_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index d4e7567b367c..0b899cb6cda1 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -724,7 +724,7 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) if (enable) { if (is_code(code, M5MOLS_RESTYPE_MONITOR)) ret = m5mols_start_monitor(info); - if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) + else if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) ret = m5mols_start_capture(info); else ret = -EINVAL; -- cgit v1.2.3 From d763448286377b8a0e3f179372e9e292bef3c337 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 11 Mar 2013 09:20:00 +0000 Subject: Btrfs: update to use fs_state bit Now that we use bit operation to check fs_state, update btrfs_free_fs_root()'s checker, otherwise we get back to memory leak case. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7d84651e850b..127b23e8323b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3253,7 +3253,7 @@ void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) if (btrfs_root_refs(&root->root_item) == 0) synchronize_srcu(&fs_info->subvol_srcu); - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { + if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { btrfs_free_log(NULL, root); btrfs_free_log_root_tree(NULL, fs_info); } -- cgit v1.2.3 From 835d974fabfa9bff4d173ad03c054ac2f673263f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 19 Mar 2013 12:13:25 -0400 Subject: Btrfs: handle a bogus chunk tree nicely If you restore a btrfs-image file system and try to mount that file system we'll panic. That's because btrfs-image restores and just makes one big chunk to envelope the whole disk, since they are really only meant to be messed with by our btrfs-progs. So fix up btrfs_rmap_block and the callers of it for mount so that we no longer panic but instead just return an error and fail to mount. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/extent-tree.c | 35 ++++++++++++++++++++++++++++++----- fs/btrfs/volumes.c | 13 ++++++++++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 350b9b18140c..a8ff25aedca1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root, cache->bytes_super += stripe_len; ret = add_excluded_extent(root, cache->key.objectid, stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { @@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root, ret = btrfs_rmap_block(&root->fs_info->mapping_tree, cache->key.objectid, bytenr, 0, &logical, &nr, &stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; while (nr--) { cache->bytes_super += stripe_len; ret = add_excluded_extent(root, logical[nr], stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) { + kfree(logical); + return ret; + } } kfree(logical); @@ -7964,7 +7969,17 @@ int btrfs_read_block_groups(struct btrfs_root *root) * info has super bytes accounted for, otherwise we'll think * we have more space than we actually do. */ - exclude_super_stripes(root, cache); + ret = exclude_super_stripes(root, cache); + if (ret) { + /* + * We may have excluded something, so call this just in + * case. + */ + free_excluded_extents(root, cache); + kfree(cache->free_space_ctl); + kfree(cache); + goto error; + } /* * check for two cases, either we are full, and therefore @@ -8106,7 +8121,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; - exclude_super_stripes(root, cache); + ret = exclude_super_stripes(root, cache); + if (ret) { + /* + * We may have excluded something, so call this just in + * case. + */ + free_excluded_extents(root, cache); + kfree(cache->free_space_ctl); + kfree(cache); + return ret; + } add_new_free_space(cache, root->fs_info, chunk_offset, chunk_offset + size); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5989a92236f7..2854c824ab64 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, em = lookup_extent_mapping(em_tree, chunk_start, 1); read_unlock(&em_tree->lock); - BUG_ON(!em || em->start != chunk_start); + if (!em) { + printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n", + chunk_start); + return -EIO; + } + + if (em->start != chunk_start) { + printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n", + em->start, chunk_start); + free_extent_map(em); + return -EIO; + } map = (struct map_lookup *)em->bdev; length = em->len; -- cgit v1.2.3 From 6113077cd319e747875ec71227d2b5cb54e08c76 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Tue, 19 Mar 2013 10:57:14 +0000 Subject: Btrfs: fix missing qgroup reservation before fallocating Steps to reproduce: mkfs.btrfs mount btrfs quota enable btrfs sub create /subv btrfs qgroup limit 10M /subv fallocate --length 20M /subv/data For the above example, fallocating will return successfully which is not expected, we try to fix it by doing qgroup reservation before fallocating. Signed-off-by: Wang Shilong Reviewed-by: Miao Xie Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 7bdb47faa12e..1be25b92d63c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2142,6 +2142,7 @@ static long btrfs_fallocate(struct file *file, int mode, { struct inode *inode = file->f_path.dentry->d_inode; struct extent_state *cached_state = NULL; + struct btrfs_root *root = BTRFS_I(inode)->root; u64 cur_offset; u64 last_byte; u64 alloc_start; @@ -2169,6 +2170,11 @@ static long btrfs_fallocate(struct file *file, int mode, ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start); if (ret) return ret; + if (root->fs_info->quota_enabled) { + ret = btrfs_qgroup_reserve(root, alloc_end - alloc_start); + if (ret) + goto out_reserve_fail; + } /* * wait for ordered IO before we have any locks. We'll loop again @@ -2272,6 +2278,9 @@ static long btrfs_fallocate(struct file *file, int mode, &cached_state, GFP_NOFS); out: mutex_unlock(&inode->i_mutex); + if (root->fs_info->quota_enabled) + btrfs_qgroup_free(root, alloc_end - alloc_start); +out_reserve_fail: /* Let go of our reservation. */ btrfs_free_reserved_data_space(inode, alloc_end - alloc_start); return ret; -- cgit v1.2.3 From d9abbf1c3131b679379762700201ae69367f3f62 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 20 Mar 2013 13:49:48 +0000 Subject: Btrfs: fix locking on ROOT_REPLACE operations in tree mod log To resolve backrefs, ROOT_REPLACE operations in the tree mod log are required to be tied to at least one KEY_REMOVE_WHILE_FREEING operation. Therefore, those operations must be enclosed by tree_mod_log_write_lock() and tree_mod_log_write_unlock() calls. Those calls are private to the tree_mod_log_* functions, which means that removal of the elements of an old root node must be logged from tree_mod_log_insert_root. This partly reverts and corrects commit ba1bfbd5 (Btrfs: fix a tree mod logging issue for root replacement operations). This fixes the brand-new version of xfstest 276 as of commit cfe73f71. Cc: stable@vger.kernel.org Signed-off-by: Jan Schmidt Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/ctree.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ecd25a1b4e51..ca9d8f1a3bb6 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -651,6 +651,8 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, if (tree_mod_dont_log(fs_info, NULL)) return 0; + __tree_mod_log_free_eb(fs_info, old_root); + ret = tree_mod_alloc(fs_info, flags, &tm); if (ret < 0) goto out; @@ -736,7 +738,7 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) static noinline void tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, - unsigned long src_offset, int nr_items) + unsigned long src_offset, int nr_items, int log_removal) { int ret; int i; @@ -750,10 +752,12 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, } for (i = 0; i < nr_items; i++) { - ret = tree_mod_log_insert_key_locked(fs_info, src, - i + src_offset, - MOD_LOG_KEY_REMOVE); - BUG_ON(ret < 0); + if (log_removal) { + ret = tree_mod_log_insert_key_locked(fs_info, src, + i + src_offset, + MOD_LOG_KEY_REMOVE); + BUG_ON(ret < 0); + } ret = tree_mod_log_insert_key_locked(fs_info, dst, i + dst_offset, MOD_LOG_KEY_ADD); @@ -927,7 +931,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ret = btrfs_dec_ref(trans, root, buf, 1, 1); BUG_ON(ret); /* -ENOMEM */ } - tree_mod_log_free_eb(root->fs_info, buf); clean_tree_block(trans, root, buf); *last_ref = 1; } @@ -1046,6 +1049,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); + tree_mod_log_free_eb(root->fs_info, buf); btrfs_free_tree_block(trans, root, buf, parent_start, last_ref); } @@ -1750,7 +1754,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, goto enospc; } - tree_mod_log_free_eb(root->fs_info, root->node); tree_mod_log_set_root_pointer(root, child); rcu_assign_pointer(root->node, child); @@ -2995,7 +2998,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, push_items = min(src_nritems - 8, push_items); tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, - push_items); + push_items, 1); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(0), @@ -3066,7 +3069,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans, sizeof(struct btrfs_key_ptr)); tree_mod_log_eb_copy(root->fs_info, dst, src, 0, - src_nritems - push_items, push_items); + src_nritems - push_items, push_items, 1); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(src_nritems - push_items), @@ -3218,12 +3221,18 @@ static noinline int split_node(struct btrfs_trans_handle *trans, int mid; int ret; u32 c_nritems; + int tree_mod_log_removal = 1; c = path->nodes[level]; WARN_ON(btrfs_header_generation(c) != trans->transid); if (c == root->node) { /* trying to split the root, lets make a new one */ ret = insert_new_root(trans, root, path, level + 1); + /* + * removal of root nodes has been logged by + * tree_mod_log_set_root_pointer due to locking + */ + tree_mod_log_removal = 0; if (ret) return ret; } else { @@ -3261,7 +3270,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans, (unsigned long)btrfs_header_chunk_tree_uuid(split), BTRFS_UUID_SIZE); - tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid); + tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid, + tree_mod_log_removal); copy_extent_buffer(split, c, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(mid), -- cgit v1.2.3 From 1dd05682b3ef6e70409e130bfd83e91770801589 Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Thu, 21 Mar 2013 04:32:32 +0000 Subject: Btrfs: fix memory leak in btrfs_create_tree() We should free leaf and root before returning from the error handling code. Signed-off-by: Tsutomu Itoh Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 127b23e8323b..6d19a0a554aa 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1291,6 +1291,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, 0, objectid, NULL, 0, 0, 0); if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); + leaf = NULL; goto fail; } @@ -1334,11 +1335,16 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, btrfs_tree_unlock(leaf); + return root; + fail: - if (ret) - return ERR_PTR(ret); + if (leaf) { + btrfs_tree_unlock(leaf); + free_extent_buffer(leaf); + } + kfree(root); - return root; + return ERR_PTR(ret); } static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, -- cgit v1.2.3 From f564c24103f87dc740c1c293c975565ac46b12ef Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 21 Mar 2013 17:32:36 -0700 Subject: x86, microcode_intel_early: Mark apply_microcode_early() as cpuinit Add missing __cpuinit annotation to apply_microcode_early(). Reported-by: Shaun Ruffell Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20130320170310.GA23362@digium.com Signed-off-by: H. Peter Anvin --- arch/x86/kernel/microcode_intel_early.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c index 5992ee8086b7..d893e8ed8ac9 100644 --- a/arch/x86/kernel/microcode_intel_early.c +++ b/arch/x86/kernel/microcode_intel_early.c @@ -659,8 +659,8 @@ static inline void __cpuinit print_ucode(struct ucode_cpu_info *uci) } #endif -static int apply_microcode_early(struct mc_saved_data *mc_saved_data, - struct ucode_cpu_info *uci) +static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data, + struct ucode_cpu_info *uci) { struct microcode_intel *mc_intel; unsigned int val[2]; -- cgit v1.2.3 From d31c3a81893e3416ea519d1b1383f319c046641f Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 4 Mar 2013 23:03:19 +0200 Subject: omapfb: fix broken build on OMAP1 Fix the following build regression in 3.9-rc1 by including : drivers/video/omap/omapfb_main.c: In function 'set_fb_var': drivers/video/omap/omapfb_main.c:505:3: error: implicit declaration of function 'cpu_is_omap15xx' [-Werror=implicit-function-declaration] Signed-off-by: Aaro Koskinen Signed-off-by: Tomi Valkeinen --- drivers/video/omap/omapfb_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index e31f5b33b501..d40612c31a98 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -32,6 +32,8 @@ #include +#include + #include "omapfb.h" #include "lcdc.h" -- cgit v1.2.3 From a2f9b2a5607e494e6b98b0101aaa731b42454ad0 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sun, 17 Feb 2013 02:43:12 +0200 Subject: OMAPDSS: tpo-td043 panel: fix data passing between SPI/DSS parts This driver uses omap_dss_device that it gets from a board file through SPI platfrom_data pointer to pass data from SPI to DSS portion of the driver by using dev_set_drvdata(). However this trick no longer works, as DSS core no longer uses omap_dss_device from a board file to create the real device, so use a global pointer to accomplish this instead, like other SPI panel drivers do. Signed-off-by: Grazvydas Ignotas Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-tpo-td043mtea1.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 6b6643911d29..048c98381ef6 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -63,6 +63,9 @@ struct tpo_td043_device { u32 power_on_resume:1; }; +/* used to pass spi_device from SPI to DSS portion of the driver */ +static struct tpo_td043_device *g_tpo_td043; + static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) { struct spi_message m; @@ -403,7 +406,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) static int tpo_td043_probe(struct omap_dss_device *dssdev) { - struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + struct tpo_td043_device *tpo_td043 = g_tpo_td043; int nreset_gpio = dssdev->reset_gpio; int ret = 0; @@ -440,6 +443,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) if (ret) dev_warn(&dssdev->dev, "failed to create sysfs files\n"); + dev_set_drvdata(&dssdev->dev, tpo_td043); + return 0; fail_gpio_req: @@ -505,6 +510,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi) return -ENODEV; } + if (g_tpo_td043 != NULL) + return -EBUSY; + spi->bits_per_word = 16; spi->mode = SPI_MODE_0; @@ -521,7 +529,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi) tpo_td043->spi = spi; tpo_td043->nreset_gpio = dssdev->reset_gpio; dev_set_drvdata(&spi->dev, tpo_td043); - dev_set_drvdata(&dssdev->dev, tpo_td043); + g_tpo_td043 = tpo_td043; omap_dss_register_driver(&tpo_td043_driver); @@ -534,6 +542,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi) omap_dss_unregister_driver(&tpo_td043_driver); kfree(tpo_td043); + g_tpo_td043 = NULL; return 0; } -- cgit v1.2.3 From ff588d83bf12fe05521a64e85dd4e2b848c0b20d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 5 Mar 2013 19:47:50 +0530 Subject: omapdss: features: fix supported outputs for OMAP4 The support outputs struct for overlay managers is incorrect for OMAP4. Make these changes: - DPI isn't supported via the LCD1 overlay manager, remove DPI as a supported output. - the TV manager can suppport DPI, but the omapdss driver doesn't support that yet, we require some muxing at the DSS level, and we also need to configure the hdmi pll in the DPI driver so that the TV manager has a pixel clock. We don't support that yet. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index d7d66ef5cb58..7f791aeda4d2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -202,12 +202,10 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { /* OMAP_DSS_CHANNEL_LCD */ - OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | - OMAP_DSS_OUTPUT_DSI1, + OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1, /* OMAP_DSS_CHANNEL_DIGIT */ - OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | - OMAP_DSS_OUTPUT_DPI, + OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI, /* OMAP_DSS_CHANNEL_LCD2 */ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | -- cgit v1.2.3 From c24a34dbcd93ef3172ecd4e5ce533fe365d4554e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 21 Mar 2013 20:43:54 +0100 Subject: ASoC: cs4271: switch to mute_stream Use the newly introduced mute_stream DAI operation, and don't mute the codec if it's called for the _CAPTURE stream. Signed-off-by: Daniel Mack Acked-by: Alexander Sverdlin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index ac0d3b4844a8..03036b326732 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -388,7 +388,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, return cs4271_set_deemph(codec); } -static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) +static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_codec *codec = dai->codec; struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); @@ -396,6 +396,9 @@ static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) int val_a = 0; int val_b = 0; + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + if (mute) { val_a = CS4271_VOLA_MUTE; val_b = CS4271_VOLB_MUTE; @@ -442,7 +445,7 @@ static const struct snd_soc_dai_ops cs4271_dai_ops = { .hw_params = cs4271_hw_params, .set_sysclk = cs4271_set_dai_sysclk, .set_fmt = cs4271_set_dai_fmt, - .digital_mute = cs4271_digital_mute, + .mute_stream = cs4271_mute_stream, }; static struct snd_soc_dai_driver cs4271_dai = { -- cgit v1.2.3 From 8abfc2608ba6f6c4bae0931149504fe33d1332a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:27:59 -0700 Subject: ASoC: pxa2xx-ac97: move EXPORT_SYMBOL_GPL() next to definition Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-ac97.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 4b0a009bd683..88d2cc6a0ae2 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -47,6 +47,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { .warm_reset = pxa2xx_ac97_warm_reset, .reset = pxa2xx_ac97_cold_reset, }; +EXPORT_SYMBOL_GPL(soc_ac97_ops); static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { .name = "AC97 PCM Stereo out", @@ -232,8 +233,6 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { }, }; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { if (pdev->id != -1) { -- cgit v1.2.3 From 949dd8c14fb2b20b4b815817e66120b22cf531d4 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 19 Mar 2013 14:35:30 -0400 Subject: xen/acpi-processor: Don't dereference struct acpi_processor on all CPUs. With git commit c705c78c0d0835a4aa5d0d9a3422e3218462030c "acpi: Export the acpi_processor_get_performance_info" we are now using a different mechanism to access the P-states. The acpi_processor per-cpu structure is set and filtered by the core ACPI code which shrinks the per_cpu contents to only online CPUs. In the past we would call acpi_processor_register_performance() which would have not tried to dereference offline cpus. With the new patch and the fact that the loop we take is for for_all_possible_cpus we end up crashing on some machines. We could modify the loop to be for online_cpus - but all the other loops in the code use possible_cpus (for a good reason) - so lets leave it as so and just check if per_cpu(processor) is NULL. With this patch we will bypass the !online but possible CPUs. This fixes: IP: [] xen_acpi_processor_init+0x1b6/0xe01 [xen_acpi_processor] PGD 4126e6067 PUD 4126e3067 PMD 0 Oops: 0002 [#1] SMP Pid: 432, comm: modprobe Not tainted 3.9.0-rc3+ #28 To be filled by O.E.M. To be filled by O.E.M./M5A97 RIP: e030:[] [] xen_acpi_processor_init+0x1b6/0xe01 [xen_acpi_processor] RSP: e02b:ffff88040c8a3ce8 EFLAGS: 00010282 .. snip.. Call Trace: [] ? read_acpi_id+0x12b/0x12b [xen_acpi_processor] [] do_one_initcall+0x12a/0x180 [] load_module+0x1cd3/0x2870 [] ? ddebug_proc_open+0xc0/0xc0 [] sys_init_module+0xd7/0x120 [] system_call_fastpath+0x16/0x1b on some machines. Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xen-acpi-processor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index f3278a6603ca..90e34ac7e522 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -505,6 +505,9 @@ static int __init xen_acpi_processor_init(void) pr = per_cpu(processors, i); perf = per_cpu_ptr(acpi_perf_data, i); + if (!pr) + continue; + pr->performance = perf; rc = acpi_processor_get_performance_info(pr); if (rc) -- cgit v1.2.3 From 909b3fdb0dd4f3db07b2d75425a00a2adb551383 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 12 Mar 2013 15:06:23 +0000 Subject: xen-pciback: notify hypervisor about devices intended to be assigned to guests For MSI-X capable devices the hypervisor wants to write protect the MSI-X table and PBA, yet it can't assume that resources have been assigned to their final values at device enumeration time. Thus have pciback do that notification, as having the device controlled by it is a prerequisite to assigning the device to guests anyway. This is the kernel part of hypervisor side commit 4245d33 ("x86/MSI: add mechanism to fully protect MSI-X table from PV guest accesses") on the master branch of git://xenbits.xen.org/xen.git. CC: stable@vger.kernel.org Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/xen/hypercall.h | 4 +-- drivers/xen/fallback.c | 3 +- drivers/xen/xen-pciback/pci_stub.c | 59 +++++++++++++++++++++++++++--------- include/xen/interface/physdev.h | 6 ++++ 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index c20d1ce62dc6..e709884d0ef9 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str) return _hypercall3(int, console_io, cmd, count, str); } -extern int __must_check HYPERVISOR_physdev_op_compat(int, void *); +extern int __must_check xen_physdev_op_compat(int, void *); static inline int HYPERVISOR_physdev_op(int cmd, void *arg) { int rc = _hypercall2(int, physdev_op, cmd, arg); if (unlikely(rc == -ENOSYS)) - rc = HYPERVISOR_physdev_op_compat(cmd, arg); + rc = xen_physdev_op_compat(cmd, arg); return rc; } diff --git a/drivers/xen/fallback.c b/drivers/xen/fallback.c index 0ef7c4d40f86..b04fb64c5a91 100644 --- a/drivers/xen/fallback.c +++ b/drivers/xen/fallback.c @@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, void *arg) } EXPORT_SYMBOL_GPL(xen_event_channel_op_compat); -int HYPERVISOR_physdev_op_compat(int cmd, void *arg) +int xen_physdev_op_compat(int cmd, void *arg) { struct physdev_op op; int rc; @@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd, void *arg) return rc; } +EXPORT_SYMBOL_GPL(xen_physdev_op_compat); diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 9204126f1560..a2278ba7fb27 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "pciback.h" #include "conf_space.h" #include "conf_space_quirks.h" @@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev) static void pcistub_device_release(struct kref *kref) { struct pcistub_device *psdev; + struct pci_dev *dev; struct xen_pcibk_dev_data *dev_data; psdev = container_of(kref, struct pcistub_device, kref); - dev_data = pci_get_drvdata(psdev->dev); + dev = psdev->dev; + dev_data = pci_get_drvdata(dev); - dev_dbg(&psdev->dev->dev, "pcistub_device_release\n"); + dev_dbg(&dev->dev, "pcistub_device_release\n"); - xen_unregister_device_domain_owner(psdev->dev); + xen_unregister_device_domain_owner(dev); /* Call the reset function which does not take lock as this * is called from "unbind" which takes a device_lock mutex. */ - __pci_reset_function_locked(psdev->dev); - if (pci_load_and_free_saved_state(psdev->dev, - &dev_data->pci_saved_state)) { - dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n"); - } else - pci_restore_state(psdev->dev); + __pci_reset_function_locked(dev); + if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) + dev_dbg(&dev->dev, "Could not reload PCI state\n"); + else + pci_restore_state(dev); + + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + struct physdev_pci_device ppdev = { + .seg = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn + }; + int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, + &ppdev); + + if (err) + dev_warn(&dev->dev, "MSI-X release failed (%d)\n", + err); + } /* Disable the device */ - xen_pcibk_reset_device(psdev->dev); + xen_pcibk_reset_device(dev); kfree(dev_data); - pci_set_drvdata(psdev->dev, NULL); + pci_set_drvdata(dev, NULL); /* Clean-up the device */ - xen_pcibk_config_free_dyn_fields(psdev->dev); - xen_pcibk_config_free_dev(psdev->dev); + xen_pcibk_config_free_dyn_fields(dev); + xen_pcibk_config_free_dev(dev); - psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; - pci_dev_put(psdev->dev); + dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; + pci_dev_put(dev); kfree(psdev); } @@ -355,6 +371,19 @@ static int pcistub_init_device(struct pci_dev *dev) if (err) goto config_release; + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + struct physdev_pci_device ppdev = { + .seg = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn + }; + + err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); + if (err) + dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", + err); + } + /* We need the device active to save the state. */ dev_dbg(&dev->dev, "save state of device\n"); pci_save_state(dev); diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 1844d31f4552..7000bb1f6e96 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -251,6 +251,12 @@ struct physdev_pci_device_add { #define PHYSDEVOP_pci_device_remove 26 #define PHYSDEVOP_restore_msi_ext 27 +/* + * Dom0 should use these two to announce MMIO resources assigned to + * MSI-X capable devices won't (prepare) or may (release) change. + */ +#define PHYSDEVOP_prepare_msix 30 +#define PHYSDEVOP_release_msix 31 struct physdev_pci_device { /* IN */ uint16_t seg; -- cgit v1.2.3 From f4541d60a449afd40448b06496dcd510f505928e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Mar 2013 17:36:09 +0000 Subject: tcp: preserve ACK clocking in TSO A long standing problem with TSO is the fact that tcp_tso_should_defer() rearms the deferred timer, while it should not. Current code leads to following bad bursty behavior : 20:11:24.484333 IP A > B: . 297161:316921(19760) ack 1 win 119 20:11:24.484337 IP B > A: . ack 263721 win 1117 20:11:24.485086 IP B > A: . ack 265241 win 1117 20:11:24.485925 IP B > A: . ack 266761 win 1117 20:11:24.486759 IP B > A: . ack 268281 win 1117 20:11:24.487594 IP B > A: . ack 269801 win 1117 20:11:24.488430 IP B > A: . ack 271321 win 1117 20:11:24.489267 IP B > A: . ack 272841 win 1117 20:11:24.490104 IP B > A: . ack 274361 win 1117 20:11:24.490939 IP B > A: . ack 275881 win 1117 20:11:24.491775 IP B > A: . ack 277401 win 1117 20:11:24.491784 IP A > B: . 316921:332881(15960) ack 1 win 119 20:11:24.492620 IP B > A: . ack 278921 win 1117 20:11:24.493448 IP B > A: . ack 280441 win 1117 20:11:24.494286 IP B > A: . ack 281961 win 1117 20:11:24.495122 IP B > A: . ack 283481 win 1117 20:11:24.495958 IP B > A: . ack 285001 win 1117 20:11:24.496791 IP B > A: . ack 286521 win 1117 20:11:24.497628 IP B > A: . ack 288041 win 1117 20:11:24.498459 IP B > A: . ack 289561 win 1117 20:11:24.499296 IP B > A: . ack 291081 win 1117 20:11:24.500133 IP B > A: . ack 292601 win 1117 20:11:24.500970 IP B > A: . ack 294121 win 1117 20:11:24.501388 IP B > A: . ack 295641 win 1117 20:11:24.501398 IP A > B: . 332881:351881(19000) ack 1 win 119 While the expected behavior is more like : 20:19:49.259620 IP A > B: . 197601:202161(4560) ack 1 win 119 20:19:49.260446 IP B > A: . ack 154281 win 1212 20:19:49.261282 IP B > A: . ack 155801 win 1212 20:19:49.262125 IP B > A: . ack 157321 win 1212 20:19:49.262136 IP A > B: . 202161:206721(4560) ack 1 win 119 20:19:49.262958 IP B > A: . ack 158841 win 1212 20:19:49.263795 IP B > A: . ack 160361 win 1212 20:19:49.264628 IP B > A: . ack 161881 win 1212 20:19:49.264637 IP A > B: . 206721:211281(4560) ack 1 win 119 20:19:49.265465 IP B > A: . ack 163401 win 1212 20:19:49.265886 IP B > A: . ack 164921 win 1212 20:19:49.266722 IP B > A: . ack 166441 win 1212 20:19:49.266732 IP A > B: . 211281:215841(4560) ack 1 win 119 20:19:49.267559 IP B > A: . ack 167961 win 1212 20:19:49.268394 IP B > A: . ack 169481 win 1212 20:19:49.269232 IP B > A: . ack 171001 win 1212 20:19:49.269241 IP A > B: . 215841:221161(5320) ack 1 win 119 Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Cc: Van Jacobson Cc: Neal Cardwell Cc: Nandita Dukkipati Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 817fbb396bc8..5d0b4387cba6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1809,8 +1809,11 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) goto send_now; } - /* Ok, it looks like it is advisable to defer. */ - tp->tso_deferred = 1 | (jiffies << 1); + /* Ok, it looks like it is advisable to defer. + * Do not rearm the timer if already set to not break TCP ACK clocking. + */ + if (!tp->tso_deferred) + tp->tso_deferred = 1 | (jiffies << 1); return true; -- cgit v1.2.3 From d137c8306c748d89260400176613b5a85574b255 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 22 Mar 2013 08:58:23 -0600 Subject: mtip32xx: fix error return code in mtip_pci_probe() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 11cc9522cdd4..92250af84e7d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -4224,6 +4224,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, dd->isr_workq = create_workqueue(dd->workq_name); if (!dd->isr_workq) { dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance); + rv = -ENOMEM; goto block_initialize_err; } @@ -4282,7 +4283,8 @@ static int mtip_pci_probe(struct pci_dev *pdev, INIT_WORK(&dd->work[7].work, mtip_workq_sdbf7); pci_set_master(pdev); - if (pci_enable_msi(pdev)) { + rv = pci_enable_msi(pdev); + if (rv) { dev_warn(&pdev->dev, "Unable to enable MSI interrupt.\n"); goto block_initialize_err; -- cgit v1.2.3 From 183cfb5720dfc393641b87710ce78561af3db6cd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 22 Mar 2013 08:59:19 -0600 Subject: loop: fix error return code in loop_add() Fix to return a negative error code from the error handling case, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Jens Axboe --- drivers/block/loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 747bb2af69dc..ee13a82f3f5e 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1623,6 +1623,7 @@ static int loop_add(struct loop_device **l, int i) goto out_free_dev; i = err; + err = -ENOMEM; lo->lo_queue = blk_alloc_queue(GFP_KERNEL); if (!lo->lo_queue) goto out_free_dev; -- cgit v1.2.3 From e651eab0af88aa7a281fe9e8c36c0846552aa7fc Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Mon, 18 Mar 2013 12:24:04 +0100 Subject: ARM: 7677/1: LPAE: Fix mapping in alloc_init_section for unaligned addresses With LPAE enabled, alloc_init_section() does not map the entire address space for unaligned addresses. The issue also reproduced with CMA + LPAE. CMA tries to map 16MB with page granularity mappings during boot. alloc_init_pte() is called and out of 16MB, only 2MB gets mapped and rest remains unaccessible. Because of this OMAP5 boot is broken with CMA + LPAE enabled. Fix the issue by ensuring that the entire addresses are mapped. Signed-off-by: R Sricharan Cc: Catalin Marinas Cc: Christoffer Dall Cc: Santosh Shilimkar Tested-by: Laura Abbott Acked-by: Catalin Marinas Acked-by: Christoffer Dall Signed-off-by: Russell King --- arch/arm/mm/mmu.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index e95a996ab78f..78978945492a 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -598,39 +598,60 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, } while (pte++, addr += PAGE_SIZE, addr != end); } -static void __init alloc_init_section(pud_t *pud, unsigned long addr, - unsigned long end, phys_addr_t phys, - const struct mem_type *type) +static void __init map_init_section(pmd_t *pmd, unsigned long addr, + unsigned long end, phys_addr_t phys, + const struct mem_type *type) { - pmd_t *pmd = pmd_offset(pud, addr); - +#ifndef CONFIG_ARM_LPAE /* - * Try a section mapping - end, addr and phys must all be aligned - * to a section boundary. Note that PMDs refer to the individual - * L1 entries, whereas PGDs refer to a group of L1 entries making - * up one logical pointer to an L2 table. + * In classic MMU format, puds and pmds are folded in to + * the pgds. pmd_offset gives the PGD entry. PGDs refer to a + * group of L1 entries making up one logical pointer to + * an L2 table (2MB), where as PMDs refer to the individual + * L1 entries (1MB). Hence increment to get the correct + * offset for odd 1MB sections. + * (See arch/arm/include/asm/pgtable-2level.h) */ - if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) { - pmd_t *p = pmd; - -#ifndef CONFIG_ARM_LPAE - if (addr & SECTION_SIZE) - pmd++; + if (addr & SECTION_SIZE) + pmd++; #endif + do { + *pmd = __pmd(phys | type->prot_sect); + phys += SECTION_SIZE; + } while (pmd++, addr += SECTION_SIZE, addr != end); - do { - *pmd = __pmd(phys | type->prot_sect); - phys += SECTION_SIZE; - } while (pmd++, addr += SECTION_SIZE, addr != end); + flush_pmd_entry(pmd); +} - flush_pmd_entry(p); - } else { +static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, + unsigned long end, phys_addr_t phys, + const struct mem_type *type) +{ + pmd_t *pmd = pmd_offset(pud, addr); + unsigned long next; + + do { /* - * No need to loop; pte's aren't interested in the - * individual L1 entries. + * With LPAE, we must loop over to map + * all the pmds for the given range. */ - alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type); - } + next = pmd_addr_end(addr, end); + + /* + * Try a section mapping - addr, next and phys must all be + * aligned to a section boundary. + */ + if (type->prot_sect && + ((addr | next | phys) & ~SECTION_MASK) == 0) { + map_init_section(pmd, addr, next, phys, type); + } else { + alloc_init_pte(pmd, addr, next, + __phys_to_pfn(phys), type); + } + + phys += next - addr; + + } while (pmd++, addr = next, addr != end); } static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, @@ -641,7 +662,7 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, do { next = pud_addr_end(addr, end); - alloc_init_section(pud, addr, next, phys, type); + alloc_init_pmd(pud, addr, next, phys, type); phys += next - addr; } while (pud++, addr = next, addr != end); } -- cgit v1.2.3 From c40e3641670eb6ebfdb71d4b0c775416ef95f4f0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 18 Mar 2013 19:44:14 +0100 Subject: ARM: 7679/1: Clear IDIVT hwcap if CONFIG_ARM_THUMB=n Don't advertise support for the SDIV/UDIV thumb instructions if the kernel is not compiled with support for thumb userspace. This is in line with how we remove the THUMB hwcap in these configurations. Acked-by: Will Deacon Cc: Stepan Moskovchenko Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 3f6cbb2e3eda..e2c8bbffb0b1 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -484,7 +484,7 @@ static void __init setup_processor(void) list->elf_name, ENDIANNESS); elf_hwcap = list->elf_hwcap; #ifndef CONFIG_ARM_THUMB - elf_hwcap &= ~HWCAP_THUMB; + elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT); #endif feat_v6_fixup(); -- cgit v1.2.3 From 8164f7af88d9ad3a757bd14f634b23997ee77f6b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 18 Mar 2013 19:44:15 +0100 Subject: ARM: 7680/1: Detect support for SDIV/UDIV from ISAR0 register The ISAR0 register indicates support for the SDIV and UDIV instructions in both the Thumb and ARM instruction set. Read the register to detect the supported instructions and update the elf_hwcap mask as appropriate. This is better than adding more and more cpuid checks in proc-v7.S for each new cpu variant that supports these instructions. Acked-by: Will Deacon Cc: Stepan Moskovchenko Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 20 ++++++++++++++++++++ arch/arm/mm/proc-v7.S | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index e2c8bbffb0b1..f3ac13f69b7a 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -353,6 +353,23 @@ void __init early_print(const char *str, ...) printk("%s", buf); } +static void __init cpuid_init_hwcaps(void) +{ + unsigned int divide_instrs; + + if (cpu_architecture() < CPU_ARCH_ARMv7) + return; + + divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24; + + switch (divide_instrs) { + case 2: + elf_hwcap |= HWCAP_IDIVA; + case 1: + elf_hwcap |= HWCAP_IDIVT; + } +} + static void __init feat_v6_fixup(void) { int id = read_cpuid_id(); @@ -483,6 +500,9 @@ static void __init setup_processor(void) snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c", list->elf_name, ENDIANNESS); elf_hwcap = list->elf_hwcap; + + cpuid_init_hwcaps(); + #ifndef CONFIG_ARM_THUMB elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT); #endif diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 3a3c015f8d5c..bcd3d48922fb 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -420,7 +420,7 @@ __v7_pj4b_proc_info: __v7_ca7mp_proc_info: .long 0x410fc070 .long 0xff0ffff0 - __v7_proc __v7_ca7mp_setup, hwcaps = HWCAP_IDIV + __v7_proc __v7_ca7mp_setup .size __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info /* @@ -430,7 +430,7 @@ __v7_ca7mp_proc_info: __v7_ca15mp_proc_info: .long 0x410fc0f0 .long 0xff0ffff0 - __v7_proc __v7_ca15mp_setup, hwcaps = HWCAP_IDIV + __v7_proc __v7_ca15mp_setup .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info /* -- cgit v1.2.3 From 120ecfafabec382c4feb79ff159ef42a39b6d33b Mon Sep 17 00:00:00 2001 From: Stepan Moskovchenko Date: Mon, 18 Mar 2013 19:44:16 +0100 Subject: ARM: 7678/1: Work around faulty ISAR0 register in some Krait CPUs Some early versions of the Krait CPU design incorrectly indicate that they only support the UDIV and SDIV instructions in Thumb mode when they actually support them in ARM and Thumb mode. It seems that these CPUs follow the DDI0406B ARM ARM which has two possible values for the divide instructions field, instead of the DDI0406C document which has three possible values. Work around this problem by checking the MIDR against Krait CPUs with this faulty ISAR0 register and force the hwcaps to indicate support in both modes. [sboyd: Rewrote commit text to reflect real reasoning now that we autodetect udiv/sdiv] Signed-off-by: Stepan Moskovchenko Acked-by: Will Deacon Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/mm/proc-v7.S | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index bcd3d48922fb..f584d3f5b37c 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -433,6 +433,21 @@ __v7_ca15mp_proc_info: __v7_proc __v7_ca15mp_setup .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info + /* + * Qualcomm Inc. Krait processors. + */ + .type __krait_proc_info, #object +__krait_proc_info: + .long 0x510f0400 @ Required ID value + .long 0xff0ffc00 @ Mask for ID + /* + * Some Krait processors don't indicate support for SDIV and UDIV + * instructions in the ARM instruction set, even though they actually + * do support them. + */ + __v7_proc __v7_setup, hwcaps = HWCAP_IDIV + .size __krait_proc_info, . - __krait_proc_info + /* * Match any ARMv7 processor core. */ -- cgit v1.2.3 From 68a154fc53ddd3f7b33e482847a411bf54a50855 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 20 Mar 2013 17:30:30 +0100 Subject: ARM: 7681/1: hw_breakpoint: use warn_once to avoid spam from reset_ctrl_regs() CPU debug features like hardware break, watchpoints can be used only when the debug mode is enabled and available. Unfortunately on OMAP4 based devices, after a CPU power cycle, the debug feature gets disabled which leads to a flood of messages coming from reset_ctrl_regs() which gets called on every CPU_PM_EXIT with CPUidle enabled. So make use of warn_once() so that system is usable. Thanks to Will for pointers and Lokesh for the analysis of the issue. Tested-by: Lokesh Vutla Signed-off-by: Santosh Shilimkar Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 96093b75ab90..5dc1aa6f0f7d 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -966,7 +966,7 @@ static void reset_ctrl_regs(void *unused) } if (err) { - pr_warning("CPU %d debug is powered down!\n", cpu); + pr_warn_once("CPU %d debug is powered down!\n", cpu); cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); return; } @@ -987,7 +987,7 @@ clear_vcr: isb(); if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { - pr_warning("CPU %d failed to disable vector catch\n", cpu); + pr_warn_once("CPU %d failed to disable vector catch\n", cpu); return; } @@ -1007,7 +1007,7 @@ clear_vcr: } if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { - pr_warning("CPU %d failed to clear debug register pairs\n", cpu); + pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu); return; } -- cgit v1.2.3 From 4080d2d11a2d572228c2b8d02406e997b87ba6a5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 14 Mar 2013 20:31:37 -0700 Subject: ARM: msm: Stop counting before reprogramming clockevent If the clockevent is forcibly reprogrammed to have a different match value we mistakenly assume the timer is not ticking and program a new match value while the timer is running. Although we clear the timer before programming a new match, it's better to stop the timer before clearing it so that we're sure the proper amount of ticks are counted. Failure to do so can lead to missed ticks and system hangs. Signed-off-by: Stephen Boyd Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 2969027f02fa..f9fd77e8f1f5 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -62,7 +62,10 @@ static int msm_timer_set_next_event(unsigned long cycles, { u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); - writel_relaxed(0, event_base + TIMER_CLEAR); + ctrl &= ~TIMER_ENABLE_EN; + writel_relaxed(ctrl, event_base + TIMER_ENABLE); + + writel_relaxed(ctrl, event_base + TIMER_CLEAR); writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); return 0; -- cgit v1.2.3 From 8761a3dc1f07b163414e2215a2cadbb4cfe2a107 Mon Sep 17 00:00:00 2001 From: Phillip Susi Date: Fri, 22 Mar 2013 12:21:53 -0600 Subject: loop: cleanup partitions when detaching loop device Any partitions added by user space to the loop device were being left in place after detaching the loop device. This was because the detach path issued a BLKRRPART to clean up partitions if LO_FLAGS_PARTSCAN was set, meaning that the partitions were auto scanned on attach. Replace this BLKRRPART with code that unconditionally cleans up partitions on detach instead. Signed-off-by: Phillip Susi Modified by Jens to export delete_partition(). Signed-off-by: Jens Axboe --- block/partition-generic.c | 1 + drivers/block/loop.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/block/partition-generic.c b/block/partition-generic.c index 789cdea05893..ae95ee6a58aa 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -257,6 +257,7 @@ void delete_partition(struct gendisk *disk, int partno) hd_struct_put(part); } +EXPORT_SYMBOL(delete_partition); static ssize_t whole_disk_show(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ee13a82f3f5e..fe5f6403417f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1044,12 +1044,29 @@ static int loop_clr_fd(struct loop_device *lo) lo->lo_state = Lo_unbound; /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) - ioctl_by_bdev(bdev, BLKRRPART, 0); lo->lo_flags = 0; if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; mutex_unlock(&lo->lo_ctl_mutex); + + /* + * Remove all partitions, since BLKRRPART won't remove user + * added partitions when max_part=0 + */ + if (bdev) { + struct disk_part_iter piter; + struct hd_struct *part; + + mutex_lock_nested(&bdev->bd_mutex, 1); + invalidate_partition(bdev->bd_disk, 0); + disk_part_iter_init(&piter, bdev->bd_disk, + DISK_PITER_INCL_EMPTY); + while ((part = disk_part_iter_next(&piter))) + delete_partition(bdev->bd_disk, part->partno); + disk_part_iter_exit(&piter); + mutex_unlock(&bdev->bd_mutex); + } + /* * Need not hold lo_ctl_mutex to fput backing file. * Calling fput holding lo_ctl_mutex triggers a circular -- cgit v1.2.3 From d2b805d89510737ea80c1469f854a16480d19778 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 22 Mar 2013 09:11:00 -0600 Subject: cciss: fix invalid use of sizeof in cciss_find_cfgtables() sizeof() when applied to a pointer typed expression gives the size of the pointer, not that of the pointed data. Signed-off-by: Wei Yongjun Acked-by: scameron@beardog.cce.hp.com Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index ade58bc8f3c4..1c1b8e544aa2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4206,7 +4206,7 @@ static int cciss_find_cfgtables(ctlr_info_t *h) if (rc) return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable)); + cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); if (!h->cfgtable) return -ENOMEM; rc = write_driver_ver_to_cfgtable(h->cfgtable); -- cgit v1.2.3 From f2fc7d0eddf86b0233faa34aa5af6780ea48bc08 Mon Sep 17 00:00:00 2001 From: Alice Ferrazzi Date: Fri, 22 Mar 2013 11:11:04 -0600 Subject: Block: blk-flush: Fixed indent code style Fixed code indent should use tabs where possible. Signed-off-by: Alice Ferrazzi Signed-off-by: Jens Axboe --- block/blk-flush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-flush.c b/block/blk-flush.c index db8f1b507857..cc2b827a853c 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -444,7 +444,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, * copied from blk_rq_pos(rq). */ if (error_sector) - *error_sector = bio->bi_sector; + *error_sector = bio->bi_sector; if (!bio_flagged(bio, BIO_UPTODATE)) ret = -EIO; -- cgit v1.2.3 From ca0ba26fbbd2d81c43085df49ce0abfe34535a90 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Mar 2013 19:56:51 +0000 Subject: efivars: Fix check for CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE The 'CONFIG_' prefix is not implicit in IS_ENABLED(). Signed-off-by: Ben Hutchings Cc: Seth Forshee Cc: Signed-off-by: Matt Fleming --- drivers/firmware/efivars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index d64661fda4fd..7acafb80fd4c 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -104,7 +104,7 @@ MODULE_VERSION(EFIVARS_VERSION); #define GUID_LEN 36 static bool efivars_pstore_disable = - IS_ENABLED(EFI_VARS_PSTORE_DEFAULT_DISABLE); + IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); -- cgit v1.2.3 From 57471c8d3c22873f70813820e6b4d2d1fea9629d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 22 Mar 2013 12:35:06 -0600 Subject: ARM: tegra: fix register address of slink controller Fix typo on register address of slink3 controller where register address is wrongly set as 0x7000d480 but it is 0x7000d800. Signed-off-by: Laxman Dewangan Cc: Signed-off-by: Stephen Warren Signed-off-by: Arnd Bergmann --- arch/arm/boot/dts/tegra20.dtsi | 2 +- arch/arm/boot/dts/tegra30.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 48d00a099ce3..3d3f64d2111a 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -385,7 +385,7 @@ spi@7000d800 { compatible = "nvidia,tegra20-slink"; - reg = <0x7000d480 0x200>; + reg = <0x7000d800 0x200>; interrupts = <0 83 0x04>; nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 9d87a3ffe998..dbf46c272562 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -372,7 +372,7 @@ spi@7000d800 { compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000d480 0x200>; + reg = <0x7000d800 0x200>; interrupts = <0 83 0x04>; nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; -- cgit v1.2.3 From e49dbbf3e770aa590a8a464ac4978a09027060b9 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 22 Mar 2013 11:18:24 -0700 Subject: nfsd: fix bad offset use vfs_writev() updates the offset argument - but the code then passes the offset to vfs_fsync_range(). Since offset now points to the offset after what was just written, this is probably not what was intended Introduced by face15025ffdf664de95e86ae831544154d26c9c "nfsd: use vfs_fsync_range(), not O_SYNC, for stable writes". Signed-off-by: Kent Overstreet Cc: Al Viro Cc: "Eric W. Biederman" Cc: stable@vger.kernel.org Reviewed-by: Zach Brown Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 2a7eb536de0b..2b2e2396a869 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1013,6 +1013,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, int host_err; int stable = *stablep; int use_wgather; + loff_t pos = offset; dentry = file->f_path.dentry; inode = dentry->d_inode; @@ -1025,7 +1026,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &pos); set_fs(oldfs); if (host_err < 0) goto out_nfserr; -- cgit v1.2.3 From c69d72aec52eb5234f433259ac5dcc3b68f1480d Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 28 Nov 2012 15:46:45 -0800 Subject: MAINTAINERS: update email address for Kevin Hilman Signed-off-by: Kevin Hilman Signed-off-by: Arnd Bergmann --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 50b4d735f961..89573ca56a1d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5675,7 +5675,7 @@ S: Maintained F: arch/arm/*omap*/*clock* OMAP POWER MANAGEMENT SUPPORT -M: Kevin Hilman +M: Kevin Hilman L: linux-omap@vger.kernel.org S: Maintained F: arch/arm/*omap*/*pm* @@ -5769,7 +5769,7 @@ F: arch/arm/*omap*/usb* OMAP GPIO DRIVER M: Santosh Shilimkar -M: Kevin Hilman +M: Kevin Hilman L: linux-omap@vger.kernel.org S: Maintained F: drivers/gpio/gpio-omap.c @@ -7165,7 +7165,7 @@ F: arch/arm/mach-s3c2410/bast-irq.c TI DAVINCI MACHINE SUPPORT M: Sekhar Nori -M: Kevin Hilman +M: Kevin Hilman L: davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers) T: git git://gitorious.org/linux-davinci/linux-davinci.git Q: http://patchwork.kernel.org/project/linux-davinci/list/ -- cgit v1.2.3 From 55e57a780a10c9fd734603ec4b32644791ef5b05 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 15 Mar 2013 09:42:12 +0000 Subject: RDMA/cxgb4: Fix error return code in create_qp() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Acked-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/qp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 17ba4f8bc12d..70b1808a08f4 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -186,8 +186,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), wq->rq.memsize, &(wq->rq.dma_addr), GFP_KERNEL); - if (!wq->rq.queue) + if (!wq->rq.queue) { + ret = -ENOMEM; goto free_sq; + } PDBG("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n", __func__, wq->sq.queue, (unsigned long long)virt_to_phys(wq->sq.queue), -- cgit v1.2.3 From 1ee9e2aa7b31427303466776f455d43e5e3c9275 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Tue, 26 Feb 2013 15:46:27 +0000 Subject: IPoIB: Fix send lockup due to missed TX completion Commit f0dc117abdfa ("IPoIB: Fix TX queue lockup with mixed UD/CM traffic") attempts to solve an issue where unprocessed UD send completions can deadlock the netdev. The patch doesn't fully resolve the issue because if more than half the tx_outstanding's were UD and all of the destinations are RC reachable, arming the CQ doesn't solve the issue. This patch uses the IB_CQ_REPORT_MISSED_EVENTS on the ib_req_notify_cq(). If the rc is above 0, the UD send cq completion callback is called directly to re-arm the send completion timer. This issue is seen in very large parallel filesystem deployments and the patch has been shown to correct the issue. Cc: Reviewed-by: Dean Luick Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 67b0c1d23678..1ef880de3a41 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -758,9 +758,13 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", tx->qp->qp_num); - if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) - ipoib_warn(priv, "request notify on send CQ failed\n"); netif_stop_queue(dev); + rc = ib_req_notify_cq(priv->send_cq, + IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS); + if (rc < 0) + ipoib_warn(priv, "request notify on send CQ failed\n"); + else if (rc) + ipoib_send_comp_handler(priv->send_cq, dev); } } } -- cgit v1.2.3 From 3c32869f7afe40ff7372e5bb7cd3d8b4520711bb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 18 Mar 2013 20:25:26 +0000 Subject: IB/ipath: Silence a static checker warning I have a static checker which complains that 0x255 is too high for the "dev->opstats[opcode]" array. It turns out that the hardware has already validated the opcode at this point so it can't actually overflow. However, silencing the warning is good and this matches how the opcode is treated in qib_ib_rcv() as well. Signed-off-by: Dan Carpenter Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 439c35d4a669..ea93870266eb 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -620,7 +620,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, goto bail; } - opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f; dev->opstats[opcode].n_bytes += tlen; dev->opstats[opcode].n_packets++; -- cgit v1.2.3 From e2eed58b4fbfe7cd59d0c9d7bec48fcfa3b2117a Mon Sep 17 00:00:00 2001 From: Vinit Agnihotri Date: Thu, 14 Mar 2013 18:13:41 +0000 Subject: IB/qib: change QLogic to Intel These changes modify the qib driver as part of acquiring the InfiniBand assets of QLogic. Reviewed-by: Mike Marciniszyn Reviewed-by: Dean Luick Signed-off-by: Vinit Agnihotri Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/Kconfig | 6 +- drivers/infiniband/hw/qib/qib_driver.c | 5 +- drivers/infiniband/hw/qib/qib_iba6120.c | 3 +- drivers/infiniband/hw/qib/qib_init.c | 8 +- drivers/infiniband/hw/qib/qib_sd7220.c | 4 +- drivers/infiniband/hw/qib/qib_verbs.c | 4 +- firmware/Makefile | 2 +- firmware/intel/sd7220.fw.ihex | 513 ++++++++++++++++++++++++++++++++ firmware/qlogic/sd7220.fw.ihex | 513 -------------------------------- 9 files changed, 530 insertions(+), 528 deletions(-) create mode 100644 firmware/intel/sd7220.fw.ihex delete mode 100644 firmware/qlogic/sd7220.fw.ihex diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig index 8349f9c5064c..1e603a375069 100644 --- a/drivers/infiniband/hw/qib/Kconfig +++ b/drivers/infiniband/hw/qib/Kconfig @@ -1,7 +1,7 @@ config INFINIBAND_QIB - tristate "QLogic PCIe HCA support" + tristate "Intel PCIe HCA support" depends on 64BIT ---help--- - This is a low-level driver for QLogic PCIe QLE InfiniBand host - channel adapters. This driver does not support the QLogic + This is a low-level driver for Intel PCIe QLE InfiniBand host + channel adapters. This driver does not support the Intel HyperTransport card (model QHT7140). diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 5423edcab51f..216092477dfc 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -63,8 +64,8 @@ MODULE_PARM_DESC(compat_ddr_negotiate, "Attempt pre-IBTA 1.2 DDR speed negotiation"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("QLogic "); -MODULE_DESCRIPTION("QLogic IB driver"); +MODULE_AUTHOR("Intel "); +MODULE_DESCRIPTION("Intel IB driver"); MODULE_VERSION(QIB_DRIVER_VERSION); /* diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index a099ac171e22..0232ae56b1fa 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation. * All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. @@ -51,7 +52,7 @@ static u32 qib_6120_iblink_state(u64); /* * This file contains all the chip-specific register information and - * access functions for the QLogic QLogic_IB PCI-Express chip. + * access functions for the Intel Intel_IB PCI-Express chip. * */ diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 50e33aa0b4e3..173f805790da 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -1138,7 +1138,7 @@ void qib_disable_after_error(struct qib_devdata *dd) static void qib_remove_one(struct pci_dev *); static int qib_init_one(struct pci_dev *, const struct pci_device_id *); -#define DRIVER_LOAD_MSG "QLogic " QIB_DRV_NAME " loaded: " +#define DRIVER_LOAD_MSG "Intel " QIB_DRV_NAME " loaded: " #define PFX QIB_DRV_NAME ": " static DEFINE_PCI_DEVICE_TABLE(qib_pci_tbl) = { @@ -1355,7 +1355,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dd = qib_init_iba6120_funcs(pdev, ent); #else qib_early_err(&pdev->dev, - "QLogic PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n", + "Intel PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n", ent->device); dd = ERR_PTR(-ENODEV); #endif @@ -1371,7 +1371,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) default: qib_early_err(&pdev->dev, - "Failing on unknown QLogic deviceid 0x%x\n", + "Failing on unknown Intel deviceid 0x%x\n", ent->device); ret = -ENODEV; } diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c index 50a8a0d4fe67..08a6c6d39e56 100644 --- a/drivers/infiniband/hw/qib/qib_sd7220.c +++ b/drivers/infiniband/hw/qib/qib_sd7220.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -44,7 +44,7 @@ #include "qib.h" #include "qib_7220.h" -#define SD7220_FW_NAME "qlogic/sd7220.fw" +#define SD7220_FW_NAME "intel/sd7220.fw" MODULE_FIRMWARE(SD7220_FW_NAME); /* diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index ba51a4715a1d..7c0ab16a2fe2 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. * @@ -2224,7 +2224,7 @@ int qib_register_ib_device(struct qib_devdata *dd) ibdev->dma_ops = &qib_dma_mapping_ops; snprintf(ibdev->node_desc, sizeof(ibdev->node_desc), - "QLogic Infiniband HCA %s", init_utsname()->nodename); + "Intel Infiniband HCA %s", init_utsname()->nodename); ret = ib_register_device(ibdev, qib_create_port_files); if (ret) diff --git a/firmware/Makefile b/firmware/Makefile index cbb09ce9730a..5d8ee1319b5c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,7 +82,7 @@ fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \ qlogic/12160.bin fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin -fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw +fw-shipped-$(CONFIG_INFINIBAND_QIB) += intel/sd7220.fw fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \ ess/maestro3_assp_minisrc.fw diff --git a/firmware/intel/sd7220.fw.ihex b/firmware/intel/sd7220.fw.ihex new file mode 100644 index 000000000000..a33636319112 --- /dev/null +++ b/firmware/intel/sd7220.fw.ihex @@ -0,0 +1,513 @@ +:10000000020A29020A87E5E630E6047F0180027FC2 +:1000100000E5E230E4047E0180027E00EE5F6008CD +:1000200053F9F7E4F5FE80087F0A121731120EA289 +:1000300075FC08E4F5FDE5E720E70343F908220035 +:1000400001201100042000755101E4F552F553F52B +:1000500052F57E7F04020438C2360552E552D3942D +:100060000C4005755201D23690070C7407F0A3744A +:10007000FFF0E4F50CA3F0900714F0A3F0750B204B +:10008000F509E4F508E508D39430400302040412AE +:100090000006150BE50870047F0180027F00E5096A +:1000A00070047E0180027E00EE5F6005121871D23E +:1000B0003553E1F7E5084509FFE50B25E025E02488 +:1000C00083F582E43407F583EFF085E220E552D32F +:1000D0009401400D1219F3E054A064407003020330 +:1000E000FB53F9F8909470E4F0E0F510AF09121E9C +:1000F000B3AF08EF4408F582758380E0F529EF443B +:1001000007121A3CF5225440D39400401EE52954AE +:10011000F070211219F3E04480F0E52254306508B4 +:1001200070091219F3E054BFF080091219F37440FA +:10013000F00203FB121A127583AE74FFF0AF087E53 +:1001400000EF4407F582E0FDE50B25E025E0248182 +:10015000F582E43407F583EDF090070EE004F0EF4C +:100160004407F582758398E0F528121A23400C1293 +:1001700019F3E04401121A320203F6AF087E00744C +:1001800080CDEFCD8D82F583E030E00A1219F3E0E7 +:100190004420F00203FB1219F3E054DFF0EE44AE0A +:1001A000121A4330E4030203FB749E121A0520E086 +:1001B000030203FB8F828E83E020E0030203FB1225 +:1001C00019F3E04410F0E5E320E708E508121A3AD5 +:1001D0004404F0AF087E00EF121A3A20E2341219FC +:1001E000F3E04408F0E5E430E6047D0180027D00A0 +:1001F000E57EC3940450047C0180027C00EC4D60D9 +:1002000005C2350203FBEE44D2121A434440F00209 +:1002100003FB1219F3E054F7F0121A127583D2E0BF +:1002200054BFF0900714E004F0E57E7003757E0182 +:10023000AF087E00121A2340121219F3E044011293 +:1002400019F2E05402121A320203FB1219F3E044CD +:10025000021219F2E054FEF0C235EE448A8F82F5A4 +:1002600083E0F517548F4440F07490FCE508440790 +:10027000FDF5828C83E0543F900702F0E054C08D7E +:10028000828C83F07492121A05900703121A197463 +:1002900082121A05900704121A1974B4121A0590E2 +:1002A0000705121A197494FEE5084406121A0AF595 +:1002B0001030E004D2378002C237E510547F8F82BD +:1002C0008E83F0304430121A035480D394004004DB +:1002D000D2398002C2398F828E83E04480F0121AB4 +:1002E000035440D394004004D23A8002C23A8F8231 +:1002F0008E83E04440F07492FEE5084406121A0A28 +:1003000030E704D2388002C2388F828E83E0547F77 +:10031000F0121E46E4F50A20030280033043031264 +:1003200019952002028003304203120C8F303006F0 +:10033000121995120C8F120D471219F3E054FBF0AD +:10034000E50AC39401404643E1081219F3E044046E +:10035000F0E5E420E72A121A127583D2E05408D39C +:10036000940040047F0180027F00E50AC3940140AD +:10037000047E0180027E00EF5E6005121DD78017AB +:10038000121A127583D2E04408F00203FB121A120B +:100390007583D2E054F7F0121E467F0812173174AD +:1003A0008EFE121A128E83E0F51054FEF0E5104412 +:1003B00001FFE508FDED4407F582EFF0E51054FE7E +:1003C000FFED4407F582EF121A11758386E04410A1 +:1003D000121A11E04410F01219F3E054FD4401FF29 +:1003E0001219F3EF121A3230320CE5084408F58284 +:1003F0007583827405F0AF0B1218D774102508F5B9 +:10040000080200850509E509D3940750030200821C +:10041000E57ED3940040047F0180027F00E57EC327 +:1004200094FA50047E0180027E00EE5F6002057E39 +:1004300030350B43E1017F0912173102005853E1B7 +:10044000FE0200588E6A8F6B8C6C8D6D756E017517 +:100450006F01757001E4F573F574F57590072FF071 +:10046000F53CF53EF546F547F53DF53FF56FE56F93 +:10047000700FE56B456A12072A758380743AF08025 +:100480000912072A758380741AF0E4F56EC3743F6D +:10049000956EFF120865758382EFF0121A4D1208EF +:1004A000C6E533F01208FA1208B140E1E56F700BAF +:1004B00012072A7583807436F0800912072A758323 +:1004C000807416F0756E0112072A7583B4E56EF01C +:1004D000121A4D743F256EF582E43400F583E5333E +:1004E000F074BF256EF582E434001208B140D8E400 +:1004F000F570F546F547F56E1208FAF583E0FE1241 +:1005000008C6E07C002400FFEC3EFEAD3BD3EF9D2F +:10051000EE9C50047B0180027B00E57070047A0140 +:1005200080027A00EB5A6006856E46757001D3EF43 +:100530009DEE9C50047F0180027F00E570B40104B1 +:100540007E0180027E00EF5E6003856E47056EE5EA +:100550006E647F70A3E5466005E547B47E0385467B +:1005600047E56F7008854676854777800EC3747FB0 +:100570009546F578C3747F9547F579E56F7037E553 +:10058000466547700C757301757401F53CF53D8047 +:1005900035E4F54EC3E5479546F53CC313F57125A3 +:1005A00046F572C3943F4005E4F53D8040C3743F77 +:1005B0009572F53D8037E5466547700F7573017597 +:1005C0007501F53EF53F754E018022E4F54EC3E519 +:1005D000479546F53EC313F5712546F572D3943F12 +:1005E0005005E4F53F8006E57224C1F53F056FE54F +:1005F0006FC39402500302046EE56D456C70028077 +:1006000004E574457590072FF07F01E53E6004E531 +:100610003C7014E4F53CF53DF53EF53F1208D27010 +:1006200004F00206A4807AE53CC3953E4007E53C11 +:10063000953EFF8006C3E53E953CFFE576D3957970 +:10064000400585767A800385797AE577C395785079 +:100650000585777B800385787BE57BD3957A403071 +:10066000E57B957AF53CF53EC3E57B957A900719D5 +:10067000F0E53CC313F571257AF572C3943F40054C +:10068000E4F53D801FC3743F9572F53DF53F80143E +:10069000E4F53CF53E900719F01208D27003F080A3 +:1006A000037401F01208657583D0E0540FFEAD3C71 +:1006B00070027E07BE0F027E80EEFBEFD39B74803C +:1006C000F898401FE4F53CF53E1208D27003F08024 +:1006D000127401F0E508FBEB4407F5827583D2E064 +:1006E0004410F0E508FBEB4409F58275839EEDF0BC +:1006F000EB4407F5827583CAEDF01208657583CC6B +:10070000EFF022E5084407F5827583BCE054F0F071 +:10071000E5084407F5827583BEE054F0F0E508442F +:1007200007F5827583C0E054F0F0E5084407F582D0 +:1007300022F0900728E0FEA3E0F5828E8322854216 +:100740004285414185404074C02FF58274023EF5D8 +:1007500083E542F074E02FF58274023EF58322E5D2 +:100760004229FDE433FCE53CC39DEC6480F87480D1 +:100770009822F583E0900722541FFDE0FAA3E0F5EC +:10078000828A83EDF022900722E0FCA3E0F5828CC0 +:100790008322900724FFED4407CFF0A3EFF02285DA +:1007A0003838853939853A3A74C02FF58274023E5B +:1007B000F58322900726FFED4407CFF0A3EFF02248 +:1007C000F074A02FF58274023EF5832274C02511C7 +:1007D000F582E43401F5832274002511F582E434B6 +:1007E00002F5832274602511F582E43403F5832237 +:1007F00074802511F582E43403F5832274E0251119 +:10080000F582E43403F5832274402511F582E43443 +:1008100006F5832274802FF58274023EF58322AFA1 +:10082000087E00EF4407F58222F583E5824407F550 +:1008300082E540F02274402511F582E43402F5830C +:100840002274C02511F582E43403F5832274002557 +:1008500011F582E43406F5832274202511F582E433 +:100860003406F58322E508FDED4407F58222E541D3 +:10087000F0E56564014564227E00FB7A00FD7C00A2 +:100880002274202511F582E434022274A02511F58A +:1008900082E4340322853E42853F418F4022853CDD +:1008A00042853D418F402275453F900720E4F0A3EB +:1008B00022F583E532F0056EE56EC3944022F0E543 +:1008C000084406F582227400256EF582E43400F5B2 +:1008D0008322E56D456C90072F22E4F9E53CD39522 +:1008E0003E2274802EF582E43402F583E02274A067 +:1008F0002EF582E43402F583E0227480256EF582C1 +:10090000E43400222542FDE433FC22854242854145 +:100910004185404022ED4C60030209E5EF4E7037FF +:10092000900726120789E0FD1207CCEDF09007280A +:10093000120789E0FD1207D8EDF0120786E0541F78 +:10094000FD120881F583EDF0900724120789E05429 +:100950001FFD120835EDF0EF64044E703790072646 +:10096000120789E0FD1207E4EDF0900728120789CD +:10097000E0FD1207F0EDF0120786E0541FFD1208AB +:100980008BF583EDF0900724120789E0541FFD12C8 +:100990000841EDF0EF64014E70047D0180027D009E +:1009A000EF64024E70047F0180027F00EF4D60789B +:1009B000900726120735E0FF1207FCEF120731E01F +:1009C000FF120808EFF0900722120735E0541FFFCE +:1009D00012084DEFF0900724120735E0541FFF1264 +:1009E0000859EFF0221207CCE4F01207D8E4F01215 +:1009F0000881F583E4F01208357414F01207E4E47A +:100A0000F01207F0E4F012088BF583E4F0120841CD +:100A10007414F01207FCE4F0120808E4F012084D18 +:100A2000E4F01208597414F02253F9F775FC10E43D +:100A3000F5FD75FE30F5FFE5E720E70343F908E52E +:100A4000E620E70B78FFE4F6D8FD53E6FE80097850 +:100A500008E4F6D8FD53E6FE758180E4F5A8D2A837 +:100A6000C2A9D2AFE5E220E50520E602800343E11A +:100A700002E5E220E00E9000007F007E08E4F0A393 +:100A8000DFFCDEFA020ADB43FA01C0E0C0F0C083FB +:100A9000C082C0D0121CE7D0D0D082D083D0F0D09A +:100AA000E053FAFE32021B55E493A3F8E493A3F655 +:100AB00008DFF98029E493A3F85407240CC8C33352 +:100AC000C4540F4420C8834004F456800146F6DF26 +:100AD000E4800B010204081020408090003FE47E77 +:100AE000019360C1A3FF543F30E509541FFEE49316 +:100AF000A360010ECF54C025E060AD40B880FE8CED +:100B0000648D658A668B67E4F569EF4E7003021D9C +:100B100055E4F568E5674566703212072A758390DB +:100B2000E41207297583C2E41207297583C4E4120D +:100B30000870702912072A758392E41207297583B9 +:100B4000C6E41207297583C8E4F0801190072612C5 +:100B50000735E41208707005120732E4F0121D55D3 +:100B6000121EBFE5674566703312072A758390E54C +:100B7000411207297583C2E5411207297583C41202 +:100B8000086E702912072A758392E54012072975AD +:100B900083C6E5401207297583C8800E9007261288 +:100BA000073512086E7006120732E540F0AF697E15 +:100BB00000AD67AC6612044412072A7583CAE0D3FD +:100BC0009400500C0568E568C394055003020B14AB +:100BD000228C608D611208DA7420400D2FF582742A +:100BE000033EF583E53EF0800B2FF58274033EF55E +:100BF00083E53CF0E53CD3953E403CE561456070C3 +:100C000010E9120904E53E120768403B120895807E +:100C100018E53EC39538401D853E38E53E600585A4 +:100C20003F3980038539398F3A120814E53E12079F +:100C3000C0E53FF0228043E5614560701912075F0F +:100C4000400512089E802712090B120814E5421273 +:100C500007C0E541F022E53CC39538401D853C388E +:100C6000E53C6005853D3980038539398F3A1208A6 +:100C700014E53C1207C0E53DF02285383885393946 +:100C8000853A3A120814E5381207C0E539F0227F98 +:100C900006121731121D23120E04120E33E0440AFD +:100CA000F0748EFE120E04120E0BEFF0E52830E504 +:100CB00003D38001C3400575142080037514081206 +:100CC0000E0475838AE514F0B4FF05751280800662 +:100CD000E514C313F512E4F516F57F121936121355 +:100CE000A3E50AC3940150090516E516C394144000 +:100CF000EAE5E420E728120E047583D2E05408D315 +:100D0000940040047F0180027F00E50AC394014003 +:100D1000047E0180027E00EF5E6003121DD7E57F36 +:100D2000C394114014120E047583D2E04480F0E5A0 +:100D3000E420E70F121DD7800A120E047583D2E05B +:100D4000547FF0121D2322748A850882F583E517EB +:100D5000F0120E3AE4F0900702E0120E177583903D +:100D6000EFF07492FEE5084407FFF5828E83E054AD +:100D7000C0FD900703E0543F4D8F828E83F09007B3 +:100D800004E0120E17758382EFF0900705E0FFED87 +:100D90004407F5827583B4EF120E03758380E05427 +:100DA000BFF030370A120E91758394E04480F03022 +:100DB000380A120E91758392E04480F0E52830E401 +:100DC0001A20390A120E04758388E0547FF0203A05 +:100DD0000A120E04758388E054BFF0748CFE120E64 +:100DE000048E83E0540F120E03758386E054BFF027 +:100DF000E5084406120DFD75838AE4F022F582753C +:100E00008382E4F0E5084407F582228E83E0F51042 +:100E100054FEF0E5104401FFE508FDED4407F582BE +:100E200022E515C45407FFE508FDED4408F5827579 +:100E3000838222758380E04440F0E5084408F5820F +:100E400075838A22E51625E025E024AFF582E43497 +:100E50001AF583E493F50D2243E11043E18053E159 +:100E6000FD85E11022E51625E025E024B2F582E4B7 +:100E7000341AF583E49322855582855483E515F071 +:100E800022E5E25420D3940022E5E25440D39400BA +:100E900022E5084406F58222FDE508FBEB4407F550 +:100EA000822253F9F775FE3022EF4E70261207CCDE +:100EB000E0FD90072612077B1207D8E0FD90072877 +:100EC00012077B120881120772120835E09007247E +:100ED000120778EF64044E70291207E4E0FD9007D2 +:100EE0002612077B1207F0E0FD90072812077B12FD +:100EF000088B120772120841E0541FFD900724125C +:100F0000077BEF64014E70047D0180027D00EF6479 +:100F1000024E70047F0180027F00EF4D60351207A2 +:100F2000FCE0FF900726120789EFF0120808E0FFA7 +:100F3000900728120789EFF012084DE0541FFF12A6 +:100F40000786EFF0120859E0541FFF90072412079C +:100F500089EFF022E4F553120E8140047F018002F4 +:100F60007F00120E8940047E0180027E00EE4F70E9 +:100F700003020FF685E11043E10253E10F85E11012 +:100F8000E4F551E5E3543FF552120E89401DAD5290 +:100F9000AF51121118EF600885E11043E140800B5A +:100FA00053E1BF120E5812000680FBE5E3543FF5F3 +:100FB00051E5E4543FF552120E81401DAD52AF5140 +:100FC000121118EF600885E11043E120800B53E116 +:100FD000DF120E5812000680FB120E8140047F01C2 +:100FE00080027F00120E8940047E0180027E00EEA6 +:100FF0004F6003120E5B22120E21EFF012109122AD +:1010000002110002104002109000000000000000D9 +:1010100001200120E4F5571216BD121644E4121007 +:10102000561214B7900726120735E4120731E4F080 +:101030001210561214B7900726120735E541120711 +:1010400031E540F0AF577E00AD567C00120444AF4E +:10105000567E000211EEFF900720A3E0FDE4F55656 +:10106000F540FEFCAB56FA1211517F0F7D18E4F5E6 +:1010700056F540FEFCAB56FA121541AF567E0012F3 +:101080001AFFE4FFF5567D1FF540FEFCAB56FA2231 +:1010900022E4F555E508FD74A0F556ED4407F55733 +:1010A000E52830E503D38001C340057F28EF8004A5 +:1010B0007F14EFC313F554E4F9120E1875838EE014 +:1010C000F510CEEFCEEED394004026E51054FE127C +:1010D0000E9875838EEDF0E5104401FDEB4407F5A5 +:1010E00082EDF0855782855683E030E301091E804A +:1010F000D4C234E9C395544002D2342202000622FD +:10110000303011901000E493F510901010E493F536 +:101110001012109012115022E4FCC3ED9FFAEFF56B +:101120008375820079FFE493CC6CCCA3D9F8DAF60E +:10113000E5E230E4028CE5ED24FFFFEF7582FFF578 +:1011400083E4936C70037F01227F00222211000050 +:10115000228E588F598C5A8D5B8A5C8B5D755E012F +:10116000E4F55FF560F56212072A7583D0E0FFC4ED +:10117000540FF561121EA585595ED3E55E955BE5BA +:101180005A12076B504B1207037583BCE0455E1281 +:1011900007297583BEE0455E1207297583C0E045C7 +:1011A0005EF0AF5FE560120878120AFFAF627E0062 +:1011B000AD5DAC5C120444E561AF5E7E00B4030536 +:1011C000121E218007AD5DAC5C121317055E021183 +:1011D0007A1207037583BCE045401207297583BE68 +:1011E000E045401207297583C0E04540F0228E5843 +:1011F0008F59755A017901755B01E4FB12072A7555 +:1012000083AEE0541AFF120865E0C4135407FEEFE2 +:10121000700CEE6535700790072FE0B4010DAF3507 +:101220007E00120EA9CFEBCF021E60E55964024585 +:101230005870047F0180027F00E559455870047E94 +:101240000180027E00EE4F602385414985404BE5D9 +:10125000594558702CAF5AFECDE9CDFCAB59AA5870 +:10126000120AFFAF5B7E00121E608015AF5B7E002E +:10127000121E60900726120735E549120731E54B2B +:10128000F0E4FDAF35FEFC120915228C648D651269 +:1012900008DA403CE56545647010120904C3E53E78 +:1012A000120769403B1208958018E53EC395384007 +:1012B0001D853E38E53E6005853F39800385393917 +:1012C0008F3A1207A8E53E120753E53FF022803B14 +:1012D000E5654564701112075F400512089E801F86 +:1012E00012073EE541F022E53CC39538401D853CA0 +:1012F00038E53C6005853D3980038539398F3A12E0 +:1013000007A8E53C120753E53DF02212079FE53898 +:10131000120753E539F0228C638D641208DA403CE1 +:10132000E56445637010120904C3E53E1207694085 +:101330003B1208958018E53EC39538401D853E3820 +:10134000E53E6005853F3980038539398F3A1207BC +:10135000A8E53E120753E53FF022803BE564456374 +:10136000701112075F400512089E801F12073EE5AC +:1013700041F022E53CC39538401D853C38E53C6092 +:1013800005853D3980038539398F3A1207A8E53C38 +:10139000120753E53DF02212079FE538120753E587 +:1013A00039F022E50DFEE5088E544405F555751516 +:1013B0000FF582120E7A1217A320310575150380DE +:1013C0000375150BE50AC39401503812142020311F +:1013D0000605150515800415151515E50AC39401B4 +:1013E0005021121420203104051580021515E50A3C +:1013F000C39401500E120E771217A3203105051564 +:10140000120E77E515B408047F0180027F00E51510 +:10141000B407047E0180027E00EE4F6002057F2249 +:10142000855582855483E515F01217A32212072AE9 +:101430007583AE74FF120729E0541AF534E0C41323 +:101440005407F53524FE602424FE603C24047063B8 +:1014500075312DE508FD74B612079274BC90072211 +:1014600012079574901207B37492803C75313AE577 +:1014700008FD74BA12079274C09007221207B6745E +:10148000C41207B374C88020753135E508FD74B8FF +:1014900012079274BEFFED4407900722CFF0A3EF2E +:1014A000F074C21207B374C6FFED4407A3CFF0A3D4 +:1014B000EFF022753401228E588F598C5A8D5B8A39 +:1014C0005C8B5D755E01E4F55F121EA585595ED3E8 +:1014D000E55E955BE55A12076B5057E55D455C701C +:1014E0003012072A758392E55E1207297583C6E5D7 +:1014F0005E1207297583C8E55E120729758390E59A +:101500005E1207297583C2E55E1207297583C480C0 +:1015100003120732E55EF0AF5F7E00AD5DAC5C129A +:101520000444AF5E7E00AD5DAC5C120BD1055E0283 +:1015300014CFAB5DAA5CAD5BAC5AAF59AE58021B81 +:10154000FB8C5C8D5D8A5E8B5F756001E4F561F5F7 +:1015500062F563121EA58F60D3E560955DE55C12B0 +:10156000076B5061E55F455E702712072A7583B6E9 +:10157000E5601207297583B8E5601207297583BAFB +:10158000E560F0AF617E00E56212087A120AFF8022 +:1015900019900724120735E56012072975838EE438 +:1015A0001207297401120729E4F0AF637E00AD5FD2 +:1015B000AC5E120444AF607E00AD5FAC5E12128B75 +:1015C00005600215582290114DE49390072EF012F9 +:1015D000081F7583AEE0541AF5347067EF4407F5C1 +:1015E000827583CEE0FF1313135407F536540FD3DF +:1015F0009400400612142D121BA9E536540F24FE48 +:10160000600C14600C146019240370378010021EE3 +:1016100091121E9112072A7583CEE054EFF0021D3D +:10162000AE121014E4F555121D850555E555C39409 +:101630000540F412072A7583CEE054C7120729E04B +:101640004408F022E4F558F559AF08EF4407F58255 +:101650007583D0E0FDC4540FF55AEF4407F5827549 +:1016600083807401F0120821758382E545F0EF4410 +:1016700007F58275838A74FFF0121A4D12072A75D6 +:1016800083BCE054EF1207297583BEE054EF1207C4 +:10169000297583C0E054EF1207297583BCE044101C +:1016A0001207297583BEE044101207297583C0E034 +:1016B0004410F0AF58E559120878020AFFE4F558D3 +:1016C0007D01F559AF35FEFC12091512072A758305 +:1016D000B674101207297583B87410120729758320 +:1016E000BA74101207297583BC7410120729758308 +:1016F000BE74101207297583C074101207297583F0 +:1017000090E41207297583C2E41207297583C4E4A3 +:10171000120729758392E41207297583C6E412071C +:10172000297583C8E4F0AF58FEE55912087A020A19 +:10173000FFE5E230E46CE5E754C064407064E5091D +:10174000C45430FEE50825E025E054C04EFEEF54B9 +:101750003F4EFDE52BAE2A7802C333CE33CED8F907 +:10176000F5828E83EDF0E52BAE2A7802C333CE33BB +:10177000CED8F9FFF5828E83A3E5FEF08F828E83AB +:10178000A3A3E5FDF08F828E83A3A3A3E5FCF0C3A2 +:10179000E52B94FAE52A94005008052BE52B7002FE +:1017A000052A22E4FFE4F558F556F5577482FC1239 +:1017B0000E048C83E0F510547FF0E5104480120E87 +:1017C00098EDF07E0A120E047583A0E020E026DE7C +:1017D000F40557E55770020556E5142401FDE4337E +:1017E000FCD3E5579DE5569C40D9E50A942050026C +:1017F000050A43E108C231120E047583A6E05512B2 +:1018000065127003D23122C23122900726E0FAA37A +:10181000E0F5828A83E0F541E539C395414026E54C +:10182000399541C39FEE12076B40047C0180027C16 +:1018300000E541643F60047B0180027B00EC5B605B +:101840002905418028C3E5419539C39FEE12076BF6 +:1018500040047F0180027F00E54160047E01800238 +:101860007E00EF5E600415418003853941853A4072 +:1018700022E5E230E460E5E130E25BE50970047FF7 +:101880000180027F00E50870047E0180027E00EE88 +:101890005F604353F9F8E5E230E43BE5E130E22EE6 +:1018A00043FA0253FAFBE4F510909470E510F0E56A +:1018B000E130E2E7909470E06510600343FA0405BC +:1018C00010909470E510F070E612000680E153FA73 +:1018D000FD53FAFB80C0228F54120006E5E130E090 +:1018E000047F0180027F00E57ED3940540047E01E1 +:1018F00080027E00EE4F603D855411E5E220E1322A +:1019000074CE121A0530E7047D0180027D008F82BB +:101910008E83E030E6047F0180027F00EF5D70156A +:101920001215C674CE121A0530E607E04480F04363 +:10193000F98012187122120E44E51625E025E024E4 +:10194000B0F582E4341AF583E493F50FE51625E04B +:1019500025E024B1F582E4341AF583E493F50E1200 +:101960000E65F510E50F54F0120E1775838CEFF02D +:10197000E50F30E00C120E04758386E04440F080E1 +:101980000A120E04758386E054BFF0120E9175831F +:1019900082E50EF0227F05121731120E04120E336B +:1019A0007402F0748EFE120E04120E0BEFF0751519 +:1019B00070120FF72034057515108003751550123D +:1019C0000FF72034047410800274F02515F51512F9 +:1019D0000E21EFF0121091203417E5156430600CE1 +:1019E00074102515F515B48003E4F515120E21EFDA +:1019F000F022F0E50B25E025E02482F582E43407AF +:101A0000F583227488FEE5084407FFF5828E83E0A3 +:101A100022F0E5084407F58222F0E054C08F828E60 +:101A200083F022EF4407F582758386E05410D39447 +:101A30000022F0900715E004F0224406F582758339 +:101A40009EE022FEEF4407F5828E83E022E49007B9 +:101A50002AF0A3F012072A758382E0547F12072927 +:101A6000E04480F01210FC12081F7583A0E020E013 +:101A70001A90072BE004F0700690072AE004F0901B +:101A8000072AE0B410E1A3E0B400DCEE44A6FCEFCA +:101A90004407F5828C83E0F532EE44A8FEEF44075C +:101AA000F5828E83E0F5332201201100042000909E +:101AB00000200F9200210F9400220F9600230F9810 +:101AC00000240F9A00250F9C00260F9E00270FA0D0 +:101AD000012001A2012101A4012201A6012301A8E4 +:101AE000012401AA012501AC012601AE012701B0A4 +:101AF000012801B400280FB640280FB8612801CB97 +:101B0000EFCBCAEECA7F01E4FDEB4A7024E508F58D +:101B10008274B6120829E508F58274B8120829E51E +:101B200008F58274BA1208297E007C00120AFF8030 +:101B300012900726120735E541F090072412073569 +:101B4000E540F012072A75838EE41207297401120A +:101B50000729E4F022E4F526F52753E1FEF52A757E +:101B60002B01F5087F0112173130301C901AA9E4BF +:101B700093F510901FF9E493F510900041E493F56C +:101B800010901ECAE493F5107F02121731120F5401 +:101B90007F03121731120006E5E230E70912100048 +:101BA00030300312110002004712081F7583D0E085 +:101BB000C4540FFD7543017544FF1208AA7404F064 +:101BC000753B01ED14600C14600B14600F2403705E +:101BD0000B800980001208A704F080061208A77481 +:101BE00004F0EE4482FEEF4407F5828E83E5451251 +:101BF00008BE758382E531F002114C8E608F611250 +:101C00001EA5E4FFCEEDCEEED39561E56012076B25 +:101C1000403974202EF582E43403F583E07003FF2D +:101C200080261208E2FDC39F401ECFEDCFEB4A7025 +:101C30000B8D421208EEF5418E40800C1208E2F541 +:101C4000381208EEF5398E3A1E80BC22755801E52F +:101C500035700C1207CCE0F54A1207D8E0F54CE5D8 +:101C600035B4040C1207E4E0F54A1207F0E0F54C35 +:101C7000E535B401047F0180027F00E535B402043C +:101C80007E0180027E00EE4F600C1207FCE0F54AF8 +:101C9000120808E0F54C85414985404B22755B01EF +:101CA000900724120735E0541FFFD3940250048F8D +:101CB000588005EF24FEF558EFC394184005755978 +:101CC000188004EF04F55985435AAF587E00AD598A +:101CD0007C00AB5B7A00121541AF5A7E0012180AE5 +:101CE000AF5B7E00021AFFE5E230E70E121003C27E +:101CF000303030031210FF203328E5E730E70512BB +:101D00000EA2800DE5FEC394205006120EA243F9E8 +:101D100008E5F230E70353F97FE5F15470D39400FE +:101D200050D822120E04758380E4F0E508440712AF +:101D30000DFD758384120E02758386120E02758363 +:101D40008CE054F3120E0375838E120E0275839489 +:101D5000E054FBF02212072A75838EE412072974DF +:101D600001120729E41208BE75838CE04420120892 +:101D7000BEE054DFF07484850882F583E0547FF080 +:101D8000E04480F022755601E4FDF557AF35FEFCC6 +:101D9000120915121C9D121E7A121C4CAF577E00A0 +:101DA000AD567C00120444AF567E000211EE75560B +:101DB00001E4FDF557AF35FEFC120915121C9D120A +:101DC0001E7A121C4CAF577E00AD567C00120444A4 +:101DD000AF567E000211EEE4F516120E44FEE50841 +:101DE0004405FF120E658F828E83F00516E516C33B +:101DF000941440E6E508120E2BE4F022E4F558F5C1 +:101E000059F55AFFFEAD58FC1209157F047E00AD4E +:101E1000587C001209157F027E00AD587C00020933 +:101E200015E53C253EFCE5422400FBE433FAECC317 +:101E30009BEA12076B400B8C42E53D253FF5418F35 +:101E4000402212090B227484F5188508198519821D +:101E5000851883E0547FF0E04480F0E04480F02275 +:101E6000EF4E700B12072A7583D2E054DFF0221276 +:101E7000072A7583D2E04420F02275580190072686 +:101E8000120735E0543FF541120732E0543FF54068 +:101E900022755602E4F557121DFCAF577E00AD5671 +:101EA0007C00020444E4F542F541F540F538F5398B +:101EB000F53A22EF5407FFE5F954F84FF5F9227F80 +:101EC00001E4FE0F0EBEFFFB2201200001042000F2 +:101ED0000000000000000000000000000000000002 +:101EE00000000000000000000000000000000000F2 +:101EF00000000000000000000000000000000000E2 +:101F000000000000000000000000000000000000D1 +:101F100000000000000000000000000000000000C1 +:101F200000000000000000000000000000000000B1 +:101F300000000000000000000000000000000000A1 +:101F40000000000000000000000000000000000091 +:101F50000000000000000000000000000000000081 +:101F60000000000000000000000000000000000071 +:101F70000000000000000000000000000000000061 +:101F80000000000000000000000000000000000051 +:101F90000000000000000000000000000000000041 +:101FA0000000000000000000000000000000000031 +:101FB0000000000000000000000000000000000021 +:101FC0000000000000000000000000000000000011 +:101FD0000000000000000000000000000000000001 +:101FE00000000000000000000000000000000000F1 +:101FF000000000000000000001201100042000810A +:00000001FF diff --git a/firmware/qlogic/sd7220.fw.ihex b/firmware/qlogic/sd7220.fw.ihex deleted file mode 100644 index a33636319112..000000000000 --- a/firmware/qlogic/sd7220.fw.ihex +++ /dev/null @@ -1,513 +0,0 @@ -:10000000020A29020A87E5E630E6047F0180027FC2 -:1000100000E5E230E4047E0180027E00EE5F6008CD -:1000200053F9F7E4F5FE80087F0A121731120EA289 -:1000300075FC08E4F5FDE5E720E70343F908220035 -:1000400001201100042000755101E4F552F553F52B -:1000500052F57E7F04020438C2360552E552D3942D -:100060000C4005755201D23690070C7407F0A3744A -:10007000FFF0E4F50CA3F0900714F0A3F0750B204B -:10008000F509E4F508E508D39430400302040412AE -:100090000006150BE50870047F0180027F00E5096A -:1000A00070047E0180027E00EE5F6005121871D23E -:1000B0003553E1F7E5084509FFE50B25E025E02488 -:1000C00083F582E43407F583EFF085E220E552D32F -:1000D0009401400D1219F3E054A064407003020330 -:1000E000FB53F9F8909470E4F0E0F510AF09121E9C -:1000F000B3AF08EF4408F582758380E0F529EF443B -:1001000007121A3CF5225440D39400401EE52954AE -:10011000F070211219F3E04480F0E52254306508B4 -:1001200070091219F3E054BFF080091219F37440FA -:10013000F00203FB121A127583AE74FFF0AF087E53 -:1001400000EF4407F582E0FDE50B25E025E0248182 -:10015000F582E43407F583EDF090070EE004F0EF4C -:100160004407F582758398E0F528121A23400C1293 -:1001700019F3E04401121A320203F6AF087E00744C -:1001800080CDEFCD8D82F583E030E00A1219F3E0E7 -:100190004420F00203FB1219F3E054DFF0EE44AE0A -:1001A000121A4330E4030203FB749E121A0520E086 -:1001B000030203FB8F828E83E020E0030203FB1225 -:1001C00019F3E04410F0E5E320E708E508121A3AD5 -:1001D0004404F0AF087E00EF121A3A20E2341219FC -:1001E000F3E04408F0E5E430E6047D0180027D00A0 -:1001F000E57EC3940450047C0180027C00EC4D60D9 -:1002000005C2350203FBEE44D2121A434440F00209 -:1002100003FB1219F3E054F7F0121A127583D2E0BF -:1002200054BFF0900714E004F0E57E7003757E0182 -:10023000AF087E00121A2340121219F3E044011293 -:1002400019F2E05402121A320203FB1219F3E044CD -:10025000021219F2E054FEF0C235EE448A8F82F5A4 -:1002600083E0F517548F4440F07490FCE508440790 -:10027000FDF5828C83E0543F900702F0E054C08D7E -:10028000828C83F07492121A05900703121A197463 -:1002900082121A05900704121A1974B4121A0590E2 -:1002A0000705121A197494FEE5084406121A0AF595 -:1002B0001030E004D2378002C237E510547F8F82BD -:1002C0008E83F0304430121A035480D394004004DB -:1002D000D2398002C2398F828E83E04480F0121AB4 -:1002E000035440D394004004D23A8002C23A8F8231 -:1002F0008E83E04440F07492FEE5084406121A0A28 -:1003000030E704D2388002C2388F828E83E0547F77 -:10031000F0121E46E4F50A20030280033043031264 -:1003200019952002028003304203120C8F303006F0 -:10033000121995120C8F120D471219F3E054FBF0AD -:10034000E50AC39401404643E1081219F3E044046E -:10035000F0E5E420E72A121A127583D2E05408D39C -:10036000940040047F0180027F00E50AC3940140AD -:10037000047E0180027E00EF5E6005121DD78017AB -:10038000121A127583D2E04408F00203FB121A120B -:100390007583D2E054F7F0121E467F0812173174AD -:1003A0008EFE121A128E83E0F51054FEF0E5104412 -:1003B00001FFE508FDED4407F582EFF0E51054FE7E -:1003C000FFED4407F582EF121A11758386E04410A1 -:1003D000121A11E04410F01219F3E054FD4401FF29 -:1003E0001219F3EF121A3230320CE5084408F58284 -:1003F0007583827405F0AF0B1218D774102508F5B9 -:10040000080200850509E509D3940750030200821C -:10041000E57ED3940040047F0180027F00E57EC327 -:1004200094FA50047E0180027E00EE5F6002057E39 -:1004300030350B43E1017F0912173102005853E1B7 -:10044000FE0200588E6A8F6B8C6C8D6D756E017517 -:100450006F01757001E4F573F574F57590072FF071 -:10046000F53CF53EF546F547F53DF53FF56FE56F93 -:10047000700FE56B456A12072A758380743AF08025 -:100480000912072A758380741AF0E4F56EC3743F6D -:10049000956EFF120865758382EFF0121A4D1208EF -:1004A000C6E533F01208FA1208B140E1E56F700BAF -:1004B00012072A7583807436F0800912072A758323 -:1004C000807416F0756E0112072A7583B4E56EF01C -:1004D000121A4D743F256EF582E43400F583E5333E -:1004E000F074BF256EF582E434001208B140D8E400 -:1004F000F570F546F547F56E1208FAF583E0FE1241 -:1005000008C6E07C002400FFEC3EFEAD3BD3EF9D2F -:10051000EE9C50047B0180027B00E57070047A0140 -:1005200080027A00EB5A6006856E46757001D3EF43 -:100530009DEE9C50047F0180027F00E570B40104B1 -:100540007E0180027E00EF5E6003856E47056EE5EA -:100550006E647F70A3E5466005E547B47E0385467B -:1005600047E56F7008854676854777800EC3747FB0 -:100570009546F578C3747F9547F579E56F7037E553 -:10058000466547700C757301757401F53CF53D8047 -:1005900035E4F54EC3E5479546F53CC313F57125A3 -:1005A00046F572C3943F4005E4F53D8040C3743F77 -:1005B0009572F53D8037E5466547700F7573017597 -:1005C0007501F53EF53F754E018022E4F54EC3E519 -:1005D000479546F53EC313F5712546F572D3943F12 -:1005E0005005E4F53F8006E57224C1F53F056FE54F -:1005F0006FC39402500302046EE56D456C70028077 -:1006000004E574457590072FF07F01E53E6004E531 -:100610003C7014E4F53CF53DF53EF53F1208D27010 -:1006200004F00206A4807AE53CC3953E4007E53C11 -:10063000953EFF8006C3E53E953CFFE576D3957970 -:10064000400585767A800385797AE577C395785079 -:100650000585777B800385787BE57BD3957A403071 -:10066000E57B957AF53CF53EC3E57B957A900719D5 -:10067000F0E53CC313F571257AF572C3943F40054C -:10068000E4F53D801FC3743F9572F53DF53F80143E -:10069000E4F53CF53E900719F01208D27003F080A3 -:1006A000037401F01208657583D0E0540FFEAD3C71 -:1006B00070027E07BE0F027E80EEFBEFD39B74803C -:1006C000F898401FE4F53CF53E1208D27003F08024 -:1006D000127401F0E508FBEB4407F5827583D2E064 -:1006E0004410F0E508FBEB4409F58275839EEDF0BC -:1006F000EB4407F5827583CAEDF01208657583CC6B -:10070000EFF022E5084407F5827583BCE054F0F071 -:10071000E5084407F5827583BEE054F0F0E508442F -:1007200007F5827583C0E054F0F0E5084407F582D0 -:1007300022F0900728E0FEA3E0F5828E8322854216 -:100740004285414185404074C02FF58274023EF5D8 -:1007500083E542F074E02FF58274023EF58322E5D2 -:100760004229FDE433FCE53CC39DEC6480F87480D1 -:100770009822F583E0900722541FFDE0FAA3E0F5EC -:10078000828A83EDF022900722E0FCA3E0F5828CC0 -:100790008322900724FFED4407CFF0A3EFF02285DA -:1007A0003838853939853A3A74C02FF58274023E5B -:1007B000F58322900726FFED4407CFF0A3EFF02248 -:1007C000F074A02FF58274023EF5832274C02511C7 -:1007D000F582E43401F5832274002511F582E434B6 -:1007E00002F5832274602511F582E43403F5832237 -:1007F00074802511F582E43403F5832274E0251119 -:10080000F582E43403F5832274402511F582E43443 -:1008100006F5832274802FF58274023EF58322AFA1 -:10082000087E00EF4407F58222F583E5824407F550 -:1008300082E540F02274402511F582E43402F5830C -:100840002274C02511F582E43403F5832274002557 -:1008500011F582E43406F5832274202511F582E433 -:100860003406F58322E508FDED4407F58222E541D3 -:10087000F0E56564014564227E00FB7A00FD7C00A2 -:100880002274202511F582E434022274A02511F58A -:1008900082E4340322853E42853F418F4022853CDD -:1008A00042853D418F402275453F900720E4F0A3EB -:1008B00022F583E532F0056EE56EC3944022F0E543 -:1008C000084406F582227400256EF582E43400F5B2 -:1008D0008322E56D456C90072F22E4F9E53CD39522 -:1008E0003E2274802EF582E43402F583E02274A067 -:1008F0002EF582E43402F583E0227480256EF582C1 -:10090000E43400222542FDE433FC22854242854145 -:100910004185404022ED4C60030209E5EF4E7037FF -:10092000900726120789E0FD1207CCEDF09007280A -:10093000120789E0FD1207D8EDF0120786E0541F78 -:10094000FD120881F583EDF0900724120789E05429 -:100950001FFD120835EDF0EF64044E703790072646 -:10096000120789E0FD1207E4EDF0900728120789CD -:10097000E0FD1207F0EDF0120786E0541FFD1208AB -:100980008BF583EDF0900724120789E0541FFD12C8 -:100990000841EDF0EF64014E70047D0180027D009E -:1009A000EF64024E70047F0180027F00EF4D60789B -:1009B000900726120735E0FF1207FCEF120731E01F -:1009C000FF120808EFF0900722120735E0541FFFCE -:1009D00012084DEFF0900724120735E0541FFF1264 -:1009E0000859EFF0221207CCE4F01207D8E4F01215 -:1009F0000881F583E4F01208357414F01207E4E47A -:100A0000F01207F0E4F012088BF583E4F0120841CD -:100A10007414F01207FCE4F0120808E4F012084D18 -:100A2000E4F01208597414F02253F9F775FC10E43D -:100A3000F5FD75FE30F5FFE5E720E70343F908E52E -:100A4000E620E70B78FFE4F6D8FD53E6FE80097850 -:100A500008E4F6D8FD53E6FE758180E4F5A8D2A837 -:100A6000C2A9D2AFE5E220E50520E602800343E11A -:100A700002E5E220E00E9000007F007E08E4F0A393 -:100A8000DFFCDEFA020ADB43FA01C0E0C0F0C083FB -:100A9000C082C0D0121CE7D0D0D082D083D0F0D09A -:100AA000E053FAFE32021B55E493A3F8E493A3F655 -:100AB00008DFF98029E493A3F85407240CC8C33352 -:100AC000C4540F4420C8834004F456800146F6DF26 -:100AD000E4800B010204081020408090003FE47E77 -:100AE000019360C1A3FF543F30E509541FFEE49316 -:100AF000A360010ECF54C025E060AD40B880FE8CED -:100B0000648D658A668B67E4F569EF4E7003021D9C -:100B100055E4F568E5674566703212072A758390DB -:100B2000E41207297583C2E41207297583C4E4120D -:100B30000870702912072A758392E41207297583B9 -:100B4000C6E41207297583C8E4F0801190072612C5 -:100B50000735E41208707005120732E4F0121D55D3 -:100B6000121EBFE5674566703312072A758390E54C -:100B7000411207297583C2E5411207297583C41202 -:100B8000086E702912072A758392E54012072975AD -:100B900083C6E5401207297583C8800E9007261288 -:100BA000073512086E7006120732E540F0AF697E15 -:100BB00000AD67AC6612044412072A7583CAE0D3FD -:100BC0009400500C0568E568C394055003020B14AB -:100BD000228C608D611208DA7420400D2FF582742A -:100BE000033EF583E53EF0800B2FF58274033EF55E -:100BF00083E53CF0E53CD3953E403CE561456070C3 -:100C000010E9120904E53E120768403B120895807E -:100C100018E53EC39538401D853E38E53E600585A4 -:100C20003F3980038539398F3A120814E53E12079F -:100C3000C0E53FF0228043E5614560701912075F0F -:100C4000400512089E802712090B120814E5421273 -:100C500007C0E541F022E53CC39538401D853C388E -:100C6000E53C6005853D3980038539398F3A1208A6 -:100C700014E53C1207C0E53DF02285383885393946 -:100C8000853A3A120814E5381207C0E539F0227F98 -:100C900006121731121D23120E04120E33E0440AFD -:100CA000F0748EFE120E04120E0BEFF0E52830E504 -:100CB00003D38001C3400575142080037514081206 -:100CC0000E0475838AE514F0B4FF05751280800662 -:100CD000E514C313F512E4F516F57F121936121355 -:100CE000A3E50AC3940150090516E516C394144000 -:100CF000EAE5E420E728120E047583D2E05408D315 -:100D0000940040047F0180027F00E50AC394014003 -:100D1000047E0180027E00EF5E6003121DD7E57F36 -:100D2000C394114014120E047583D2E04480F0E5A0 -:100D3000E420E70F121DD7800A120E047583D2E05B -:100D4000547FF0121D2322748A850882F583E517EB -:100D5000F0120E3AE4F0900702E0120E177583903D -:100D6000EFF07492FEE5084407FFF5828E83E054AD -:100D7000C0FD900703E0543F4D8F828E83F09007B3 -:100D800004E0120E17758382EFF0900705E0FFED87 -:100D90004407F5827583B4EF120E03758380E05427 -:100DA000BFF030370A120E91758394E04480F03022 -:100DB000380A120E91758392E04480F0E52830E401 -:100DC0001A20390A120E04758388E0547FF0203A05 -:100DD0000A120E04758388E054BFF0748CFE120E64 -:100DE000048E83E0540F120E03758386E054BFF027 -:100DF000E5084406120DFD75838AE4F022F582753C -:100E00008382E4F0E5084407F582228E83E0F51042 -:100E100054FEF0E5104401FFE508FDED4407F582BE -:100E200022E515C45407FFE508FDED4408F5827579 -:100E3000838222758380E04440F0E5084408F5820F -:100E400075838A22E51625E025E024AFF582E43497 -:100E50001AF583E493F50D2243E11043E18053E159 -:100E6000FD85E11022E51625E025E024B2F582E4B7 -:100E7000341AF583E49322855582855483E515F071 -:100E800022E5E25420D3940022E5E25440D39400BA -:100E900022E5084406F58222FDE508FBEB4407F550 -:100EA000822253F9F775FE3022EF4E70261207CCDE -:100EB000E0FD90072612077B1207D8E0FD90072877 -:100EC00012077B120881120772120835E09007247E -:100ED000120778EF64044E70291207E4E0FD9007D2 -:100EE0002612077B1207F0E0FD90072812077B12FD -:100EF000088B120772120841E0541FFD900724125C -:100F0000077BEF64014E70047D0180027D00EF6479 -:100F1000024E70047F0180027F00EF4D60351207A2 -:100F2000FCE0FF900726120789EFF0120808E0FFA7 -:100F3000900728120789EFF012084DE0541FFF12A6 -:100F40000786EFF0120859E0541FFF90072412079C -:100F500089EFF022E4F553120E8140047F018002F4 -:100F60007F00120E8940047E0180027E00EE4F70E9 -:100F700003020FF685E11043E10253E10F85E11012 -:100F8000E4F551E5E3543FF552120E89401DAD5290 -:100F9000AF51121118EF600885E11043E140800B5A -:100FA00053E1BF120E5812000680FBE5E3543FF5F3 -:100FB00051E5E4543FF552120E81401DAD52AF5140 -:100FC000121118EF600885E11043E120800B53E116 -:100FD000DF120E5812000680FB120E8140047F01C2 -:100FE00080027F00120E8940047E0180027E00EEA6 -:100FF0004F6003120E5B22120E21EFF012109122AD -:1010000002110002104002109000000000000000D9 -:1010100001200120E4F5571216BD121644E4121007 -:10102000561214B7900726120735E4120731E4F080 -:101030001210561214B7900726120735E541120711 -:1010400031E540F0AF577E00AD567C00120444AF4E -:10105000567E000211EEFF900720A3E0FDE4F55656 -:10106000F540FEFCAB56FA1211517F0F7D18E4F5E6 -:1010700056F540FEFCAB56FA121541AF567E0012F3 -:101080001AFFE4FFF5567D1FF540FEFCAB56FA2231 -:1010900022E4F555E508FD74A0F556ED4407F55733 -:1010A000E52830E503D38001C340057F28EF8004A5 -:1010B0007F14EFC313F554E4F9120E1875838EE014 -:1010C000F510CEEFCEEED394004026E51054FE127C -:1010D0000E9875838EEDF0E5104401FDEB4407F5A5 -:1010E00082EDF0855782855683E030E301091E804A -:1010F000D4C234E9C395544002D2342202000622FD -:10110000303011901000E493F510901010E493F536 -:101110001012109012115022E4FCC3ED9FFAEFF56B -:101120008375820079FFE493CC6CCCA3D9F8DAF60E -:10113000E5E230E4028CE5ED24FFFFEF7582FFF578 -:1011400083E4936C70037F01227F00222211000050 -:10115000228E588F598C5A8D5B8A5C8B5D755E012F -:10116000E4F55FF560F56212072A7583D0E0FFC4ED -:10117000540FF561121EA585595ED3E55E955BE5BA -:101180005A12076B504B1207037583BCE0455E1281 -:1011900007297583BEE0455E1207297583C0E045C7 -:1011A0005EF0AF5FE560120878120AFFAF627E0062 -:1011B000AD5DAC5C120444E561AF5E7E00B4030536 -:1011C000121E218007AD5DAC5C121317055E021183 -:1011D0007A1207037583BCE045401207297583BE68 -:1011E000E045401207297583C0E04540F0228E5843 -:1011F0008F59755A017901755B01E4FB12072A7555 -:1012000083AEE0541AFF120865E0C4135407FEEFE2 -:10121000700CEE6535700790072FE0B4010DAF3507 -:101220007E00120EA9CFEBCF021E60E55964024585 -:101230005870047F0180027F00E559455870047E94 -:101240000180027E00EE4F602385414985404BE5D9 -:10125000594558702CAF5AFECDE9CDFCAB59AA5870 -:10126000120AFFAF5B7E00121E608015AF5B7E002E -:10127000121E60900726120735E549120731E54B2B -:10128000F0E4FDAF35FEFC120915228C648D651269 -:1012900008DA403CE56545647010120904C3E53E78 -:1012A000120769403B1208958018E53EC395384007 -:1012B0001D853E38E53E6005853F39800385393917 -:1012C0008F3A1207A8E53E120753E53FF022803B14 -:1012D000E5654564701112075F400512089E801F86 -:1012E00012073EE541F022E53CC39538401D853CA0 -:1012F00038E53C6005853D3980038539398F3A12E0 -:1013000007A8E53C120753E53DF02212079FE53898 -:10131000120753E539F0228C638D641208DA403CE1 -:10132000E56445637010120904C3E53E1207694085 -:101330003B1208958018E53EC39538401D853E3820 -:10134000E53E6005853F3980038539398F3A1207BC -:10135000A8E53E120753E53FF022803BE564456374 -:10136000701112075F400512089E801F12073EE5AC -:1013700041F022E53CC39538401D853C38E53C6092 -:1013800005853D3980038539398F3A1207A8E53C38 -:10139000120753E53DF02212079FE538120753E587 -:1013A00039F022E50DFEE5088E544405F555751516 -:1013B0000FF582120E7A1217A320310575150380DE -:1013C0000375150BE50AC39401503812142020311F -:1013D0000605150515800415151515E50AC39401B4 -:1013E0005021121420203104051580021515E50A3C -:1013F000C39401500E120E771217A3203105051564 -:10140000120E77E515B408047F0180027F00E51510 -:10141000B407047E0180027E00EE4F6002057F2249 -:10142000855582855483E515F01217A32212072AE9 -:101430007583AE74FF120729E0541AF534E0C41323 -:101440005407F53524FE602424FE603C24047063B8 -:1014500075312DE508FD74B612079274BC90072211 -:1014600012079574901207B37492803C75313AE577 -:1014700008FD74BA12079274C09007221207B6745E -:10148000C41207B374C88020753135E508FD74B8FF -:1014900012079274BEFFED4407900722CFF0A3EF2E -:1014A000F074C21207B374C6FFED4407A3CFF0A3D4 -:1014B000EFF022753401228E588F598C5A8D5B8A39 -:1014C0005C8B5D755E01E4F55F121EA585595ED3E8 -:1014D000E55E955BE55A12076B5057E55D455C701C -:1014E0003012072A758392E55E1207297583C6E5D7 -:1014F0005E1207297583C8E55E120729758390E59A -:101500005E1207297583C2E55E1207297583C480C0 -:1015100003120732E55EF0AF5F7E00AD5DAC5C129A -:101520000444AF5E7E00AD5DAC5C120BD1055E0283 -:1015300014CFAB5DAA5CAD5BAC5AAF59AE58021B81 -:10154000FB8C5C8D5D8A5E8B5F756001E4F561F5F7 -:1015500062F563121EA58F60D3E560955DE55C12B0 -:10156000076B5061E55F455E702712072A7583B6E9 -:10157000E5601207297583B8E5601207297583BAFB -:10158000E560F0AF617E00E56212087A120AFF8022 -:1015900019900724120735E56012072975838EE438 -:1015A0001207297401120729E4F0AF637E00AD5FD2 -:1015B000AC5E120444AF607E00AD5FAC5E12128B75 -:1015C00005600215582290114DE49390072EF012F9 -:1015D000081F7583AEE0541AF5347067EF4407F5C1 -:1015E000827583CEE0FF1313135407F536540FD3DF -:1015F0009400400612142D121BA9E536540F24FE48 -:10160000600C14600C146019240370378010021EE3 -:1016100091121E9112072A7583CEE054EFF0021D3D -:10162000AE121014E4F555121D850555E555C39409 -:101630000540F412072A7583CEE054C7120729E04B -:101640004408F022E4F558F559AF08EF4407F58255 -:101650007583D0E0FDC4540FF55AEF4407F5827549 -:1016600083807401F0120821758382E545F0EF4410 -:1016700007F58275838A74FFF0121A4D12072A75D6 -:1016800083BCE054EF1207297583BEE054EF1207C4 -:10169000297583C0E054EF1207297583BCE044101C -:1016A0001207297583BEE044101207297583C0E034 -:1016B0004410F0AF58E559120878020AFFE4F558D3 -:1016C0007D01F559AF35FEFC12091512072A758305 -:1016D000B674101207297583B87410120729758320 -:1016E000BA74101207297583BC7410120729758308 -:1016F000BE74101207297583C074101207297583F0 -:1017000090E41207297583C2E41207297583C4E4A3 -:10171000120729758392E41207297583C6E412071C -:10172000297583C8E4F0AF58FEE55912087A020A19 -:10173000FFE5E230E46CE5E754C064407064E5091D -:10174000C45430FEE50825E025E054C04EFEEF54B9 -:101750003F4EFDE52BAE2A7802C333CE33CED8F907 -:10176000F5828E83EDF0E52BAE2A7802C333CE33BB -:10177000CED8F9FFF5828E83A3E5FEF08F828E83AB -:10178000A3A3E5FDF08F828E83A3A3A3E5FCF0C3A2 -:10179000E52B94FAE52A94005008052BE52B7002FE -:1017A000052A22E4FFE4F558F556F5577482FC1239 -:1017B0000E048C83E0F510547FF0E5104480120E87 -:1017C00098EDF07E0A120E047583A0E020E026DE7C -:1017D000F40557E55770020556E5142401FDE4337E -:1017E000FCD3E5579DE5569C40D9E50A942050026C -:1017F000050A43E108C231120E047583A6E05512B2 -:1018000065127003D23122C23122900726E0FAA37A -:10181000E0F5828A83E0F541E539C395414026E54C -:10182000399541C39FEE12076B40047C0180027C16 -:1018300000E541643F60047B0180027B00EC5B605B -:101840002905418028C3E5419539C39FEE12076BF6 -:1018500040047F0180027F00E54160047E01800238 -:101860007E00EF5E600415418003853941853A4072 -:1018700022E5E230E460E5E130E25BE50970047FF7 -:101880000180027F00E50870047E0180027E00EE88 -:101890005F604353F9F8E5E230E43BE5E130E22EE6 -:1018A00043FA0253FAFBE4F510909470E510F0E56A -:1018B000E130E2E7909470E06510600343FA0405BC -:1018C00010909470E510F070E612000680E153FA73 -:1018D000FD53FAFB80C0228F54120006E5E130E090 -:1018E000047F0180027F00E57ED3940540047E01E1 -:1018F00080027E00EE4F603D855411E5E220E1322A -:1019000074CE121A0530E7047D0180027D008F82BB -:101910008E83E030E6047F0180027F00EF5D70156A -:101920001215C674CE121A0530E607E04480F04363 -:10193000F98012187122120E44E51625E025E024E4 -:10194000B0F582E4341AF583E493F50FE51625E04B -:1019500025E024B1F582E4341AF583E493F50E1200 -:101960000E65F510E50F54F0120E1775838CEFF02D -:10197000E50F30E00C120E04758386E04440F080E1 -:101980000A120E04758386E054BFF0120E9175831F -:1019900082E50EF0227F05121731120E04120E336B -:1019A0007402F0748EFE120E04120E0BEFF0751519 -:1019B00070120FF72034057515108003751550123D -:1019C0000FF72034047410800274F02515F51512F9 -:1019D0000E21EFF0121091203417E5156430600CE1 -:1019E00074102515F515B48003E4F515120E21EFDA -:1019F000F022F0E50B25E025E02482F582E43407AF -:101A0000F583227488FEE5084407FFF5828E83E0A3 -:101A100022F0E5084407F58222F0E054C08F828E60 -:101A200083F022EF4407F582758386E05410D39447 -:101A30000022F0900715E004F0224406F582758339 -:101A40009EE022FEEF4407F5828E83E022E49007B9 -:101A50002AF0A3F012072A758382E0547F12072927 -:101A6000E04480F01210FC12081F7583A0E020E013 -:101A70001A90072BE004F0700690072AE004F0901B -:101A8000072AE0B410E1A3E0B400DCEE44A6FCEFCA -:101A90004407F5828C83E0F532EE44A8FEEF44075C -:101AA000F5828E83E0F5332201201100042000909E -:101AB00000200F9200210F9400220F9600230F9810 -:101AC00000240F9A00250F9C00260F9E00270FA0D0 -:101AD000012001A2012101A4012201A6012301A8E4 -:101AE000012401AA012501AC012601AE012701B0A4 -:101AF000012801B400280FB640280FB8612801CB97 -:101B0000EFCBCAEECA7F01E4FDEB4A7024E508F58D -:101B10008274B6120829E508F58274B8120829E51E -:101B200008F58274BA1208297E007C00120AFF8030 -:101B300012900726120735E541F090072412073569 -:101B4000E540F012072A75838EE41207297401120A -:101B50000729E4F022E4F526F52753E1FEF52A757E -:101B60002B01F5087F0112173130301C901AA9E4BF -:101B700093F510901FF9E493F510900041E493F56C -:101B800010901ECAE493F5107F02121731120F5401 -:101B90007F03121731120006E5E230E70912100048 -:101BA00030300312110002004712081F7583D0E085 -:101BB000C4540FFD7543017544FF1208AA7404F064 -:101BC000753B01ED14600C14600B14600F2403705E -:101BD0000B800980001208A704F080061208A77481 -:101BE00004F0EE4482FEEF4407F5828E83E5451251 -:101BF00008BE758382E531F002114C8E608F611250 -:101C00001EA5E4FFCEEDCEEED39561E56012076B25 -:101C1000403974202EF582E43403F583E07003FF2D -:101C200080261208E2FDC39F401ECFEDCFEB4A7025 -:101C30000B8D421208EEF5418E40800C1208E2F541 -:101C4000381208EEF5398E3A1E80BC22755801E52F -:101C500035700C1207CCE0F54A1207D8E0F54CE5D8 -:101C600035B4040C1207E4E0F54A1207F0E0F54C35 -:101C7000E535B401047F0180027F00E535B402043C -:101C80007E0180027E00EE4F600C1207FCE0F54AF8 -:101C9000120808E0F54C85414985404B22755B01EF -:101CA000900724120735E0541FFFD3940250048F8D -:101CB000588005EF24FEF558EFC394184005755978 -:101CC000188004EF04F55985435AAF587E00AD598A -:101CD0007C00AB5B7A00121541AF5A7E0012180AE5 -:101CE000AF5B7E00021AFFE5E230E70E121003C27E -:101CF000303030031210FF203328E5E730E70512BB -:101D00000EA2800DE5FEC394205006120EA243F9E8 -:101D100008E5F230E70353F97FE5F15470D39400FE -:101D200050D822120E04758380E4F0E508440712AF -:101D30000DFD758384120E02758386120E02758363 -:101D40008CE054F3120E0375838E120E0275839489 -:101D5000E054FBF02212072A75838EE412072974DF -:101D600001120729E41208BE75838CE04420120892 -:101D7000BEE054DFF07484850882F583E0547FF080 -:101D8000E04480F022755601E4FDF557AF35FEFCC6 -:101D9000120915121C9D121E7A121C4CAF577E00A0 -:101DA000AD567C00120444AF567E000211EE75560B -:101DB00001E4FDF557AF35FEFC120915121C9D120A -:101DC0001E7A121C4CAF577E00AD567C00120444A4 -:101DD000AF567E000211EEE4F516120E44FEE50841 -:101DE0004405FF120E658F828E83F00516E516C33B -:101DF000941440E6E508120E2BE4F022E4F558F5C1 -:101E000059F55AFFFEAD58FC1209157F047E00AD4E -:101E1000587C001209157F027E00AD587C00020933 -:101E200015E53C253EFCE5422400FBE433FAECC317 -:101E30009BEA12076B400B8C42E53D253FF5418F35 -:101E4000402212090B227484F5188508198519821D -:101E5000851883E0547FF0E04480F0E04480F02275 -:101E6000EF4E700B12072A7583D2E054DFF0221276 -:101E7000072A7583D2E04420F02275580190072686 -:101E8000120735E0543FF541120732E0543FF54068 -:101E900022755602E4F557121DFCAF577E00AD5671 -:101EA0007C00020444E4F542F541F540F538F5398B -:101EB000F53A22EF5407FFE5F954F84FF5F9227F80 -:101EC00001E4FE0F0EBEFFFB2201200001042000F2 -:101ED0000000000000000000000000000000000002 -:101EE00000000000000000000000000000000000F2 -:101EF00000000000000000000000000000000000E2 -:101F000000000000000000000000000000000000D1 -:101F100000000000000000000000000000000000C1 -:101F200000000000000000000000000000000000B1 -:101F300000000000000000000000000000000000A1 -:101F40000000000000000000000000000000000091 -:101F50000000000000000000000000000000000081 -:101F60000000000000000000000000000000000071 -:101F70000000000000000000000000000000000061 -:101F80000000000000000000000000000000000051 -:101F90000000000000000000000000000000000041 -:101FA0000000000000000000000000000000000031 -:101FB0000000000000000000000000000000000021 -:101FC0000000000000000000000000000000000011 -:101FD0000000000000000000000000000000000001 -:101FE00000000000000000000000000000000000F1 -:101FF000000000000000000001201100042000810A -:00000001FF -- cgit v1.2.3 From f9f475292dbb0e7035fb6661d1524761ea0888d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Mar 2013 15:04:07 +0100 Subject: cfg80211: always check for scan end on P2P device If a P2P device wdev is removed while it has a scan, then the scan completion might crash later as it is already freed by that time. To avoid the crash always check the scan completion when the P2P device is being removed for some reason. If the driver already canceled it, don't want and free it, otherwise warn and leak it to avoid later crashes. In order to do this, locking needs to be changed away from the rdev mutex (which can't always be guaranteed). For now, use the sched_scan_mtx instead, I'll rename it to just scan_mtx in a later patch. Signed-off-by: Johannes Berg --- net/wireless/core.c | 64 ++++++++++++++++++++++++++++++++++++------------- net/wireless/core.h | 3 +++ net/wireless/nl80211.c | 52 +++++++++++++++++++++------------------- net/wireless/scan.c | 8 ++++--- net/wireless/sme.c | 6 +++-- net/wireless/wext-sme.c | 6 +++++ 6 files changed, 92 insertions(+), 47 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 922002105062..11743d48cbc2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) rdev_rfkill_poll(rdev); } +void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + lockdep_assert_held(&rdev->devlist_mtx); + lockdep_assert_held(&rdev->sched_scan_mtx); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) + return; + + if (!wdev->p2p_started) + return; + + rdev_stop_p2p_device(rdev, wdev); + wdev->p2p_started = false; + + rdev->opencount--; + + if (rdev->scan_req && rdev->scan_req->wdev == wdev) { + bool busy = work_busy(&rdev->scan_done_wk); + + /* + * If the work isn't pending or running (in which case it would + * be waiting for the lock we hold) the driver didn't properly + * cancel the scan when the interface was removed. In this case + * warn and leak the scan request object to not crash later. + */ + WARN_ON(!busy); + + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev, !busy); + } +} + static int cfg80211_rfkill_set_block(void *data, bool blocked) { struct cfg80211_registered_device *rdev = data; @@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) return 0; rtnl_lock(); - mutex_lock(&rdev->devlist_mtx); + + /* read-only iteration need not hold the devlist_mtx */ list_for_each_entry(wdev, &rdev->wdev_list, list) { if (wdev->netdev) { @@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) /* otherwise, check iftype */ switch (wdev->iftype) { case NL80211_IFTYPE_P2P_DEVICE: - if (!wdev->p2p_started) - break; - rdev_stop_p2p_device(rdev, wdev); - wdev->p2p_started = false; - rdev->opencount--; + /* but this requires it */ + mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); + cfg80211_stop_p2p_device(rdev, wdev); + mutex_unlock(&rdev->sched_scan_mtx); + mutex_unlock(&rdev->devlist_mtx); break; default: break; } } - mutex_unlock(&rdev->devlist_mtx); rtnl_unlock(); return 0; @@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work) wdev = container_of(work, struct wireless_dev, cleanup_work); rdev = wiphy_to_dev(wdev->wiphy); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { rdev->scan_req->aborted = true; ___cfg80211_scan_done(rdev, true); } - cfg80211_unlock_rdev(rdev); - - mutex_lock(&rdev->sched_scan_mtx); - if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { __cfg80211_stop_sched_scan(rdev, false); @@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) return; mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); list_del_rcu(&wdev->list); rdev->devlist_generation++; switch (wdev->iftype) { case NL80211_IFTYPE_P2P_DEVICE: - if (!wdev->p2p_started) - break; - rdev_stop_p2p_device(rdev, wdev); - wdev->p2p_started = false; - rdev->opencount--; + cfg80211_stop_p2p_device(rdev, wdev); break; default: WARN_ON_ONCE(1); break; } + mutex_unlock(&rdev->sched_scan_mtx); mutex_unlock(&rdev->devlist_mtx); } EXPORT_SYMBOL(cfg80211_unregister_wdev); @@ -937,6 +965,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, cfg80211_update_iface_num(rdev, wdev->iftype, 1); cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); wdev_lock(wdev); switch (wdev->iftype) { #ifdef CONFIG_CFG80211_WEXT @@ -968,6 +997,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, break; } wdev_unlock(wdev); + mutex_unlock(&rdev->sched_scan_mtx); rdev->opencount++; mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); diff --git a/net/wireless/core.h b/net/wireless/core.h index 3aec0e429d8a..5845c2b37aa8 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -503,6 +503,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype, int num); +void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d44ab216c0ec..58e13a8c95f9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4702,14 +4702,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->scan) return -EOPNOTSUPP; - if (rdev->scan_req) - return -EBUSY; + mutex_lock(&rdev->sched_scan_mtx); + if (rdev->scan_req) { + err = -EBUSY; + goto unlock; + } if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { n_channels = validate_scan_freqs( info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); - if (!n_channels) - return -EINVAL; + if (!n_channels) { + err = -EINVAL; + goto unlock; + } } else { enum ieee80211_band band; n_channels = 0; @@ -4723,23 +4728,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) n_ssids++; - if (n_ssids > wiphy->max_scan_ssids) - return -EINVAL; + if (n_ssids > wiphy->max_scan_ssids) { + err = -EINVAL; + goto unlock; + } if (info->attrs[NL80211_ATTR_IE]) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); else ie_len = 0; - if (ie_len > wiphy->max_scan_ie_len) - return -EINVAL; + if (ie_len > wiphy->max_scan_ie_len) { + err = -EINVAL; + goto unlock; + } request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); - if (!request) - return -ENOMEM; + if (!request) { + err = -ENOMEM; + goto unlock; + } if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -4876,6 +4887,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) kfree(request); } + unlock: + mutex_unlock(&rdev->sched_scan_mtx); return err; } @@ -7749,20 +7762,9 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->stop_p2p_device) return -EOPNOTSUPP; - if (!wdev->p2p_started) - return 0; - - rdev_stop_p2p_device(rdev, wdev); - wdev->p2p_started = false; - - mutex_lock(&rdev->devlist_mtx); - rdev->opencount--; - mutex_unlock(&rdev->devlist_mtx); - - if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev, true); - } + mutex_lock(&rdev->sched_scan_mtx); + cfg80211_stop_p2p_device(rdev, wdev); + mutex_unlock(&rdev->sched_scan_mtx); return 0; } @@ -8486,7 +8488,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, struct nlattr *nest; int i; - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (WARN_ON(!req)) return 0; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e93bd31d23bb..fd99ea495b7e 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) union iwreq_data wrqu; #endif - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); request = rdev->scan_req; @@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, scan_done_wk); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); ___cfg80211_scan_done(rdev, false); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) @@ -1062,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (IS_ERR(rdev)) return PTR_ERR(rdev); + mutex_lock(&rdev->sched_scan_mtx); if (rdev->scan_req) { err = -EBUSY; goto out; @@ -1168,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, dev_hold(dev); } out: + mutex_unlock(&rdev->sched_scan_mtx); kfree(creq); cfg80211_unlock_rdev(rdev); return err; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f432bd3755b1..09d994d192ff 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) ASSERT_RTNL(); ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (rdev->scan_req) return -EBUSY; @@ -320,11 +321,9 @@ void cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; - mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); wdev_lock(wdev); __cfg80211_sme_scan_done(dev); wdev_unlock(wdev); - mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); } void cfg80211_sme_rx_auth(struct net_device *dev, @@ -924,9 +923,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, int err; mutex_lock(&rdev->devlist_mtx); + /* might request scan - scan_mtx -> wdev_mtx dependency */ + mutex_lock(&rdev->sched_scan_mtx); wdev_lock(dev->ieee80211_ptr); err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->sched_scan_mtx); mutex_unlock(&rdev->devlist_mtx); return err; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fb9622f6d99c..e79cb5c0655a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; @@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); wdev_lock(wdev); err = 0; @@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; @@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); + mutex_lock(&rdev->sched_scan_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; -- cgit v1.2.3 From 370bd005937c0e00f9104a602f9fe1dd6b21b54b Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 19 Mar 2013 17:50:50 -0700 Subject: mac80211: Don't restart sta-timer if not associated. I found another crash when deleting lots of virtual stations in a congested environment. I think the problem is that the ieee80211_mlme_notify_scan_completed could call ieee80211_restart_sta_timer for a stopped interface that was about to be deleted. With the following patch I am unable to reproduce the crash. Signed-off-by: Ben Greear [move check, also make the same change in mesh] Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 3 ++- net/mac80211/mlme.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 29ce2aa87e7b..4749b3858695 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1060,7 +1060,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) - if (ieee80211_vif_is_mesh(&sdata->vif)) + if (ieee80211_vif_is_mesh(&sdata->vif) && + ieee80211_sdata_running(sdata)) ieee80211_queue_work(&local->hw, &sdata->work); rcu_read_unlock(); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 141577412d84..82cc30318a86 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3608,8 +3608,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) /* Restart STA timers */ rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - ieee80211_restart_sta_timer(sdata); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (ieee80211_sdata_running(sdata)) + ieee80211_restart_sta_timer(sdata); + } rcu_read_unlock(); } -- cgit v1.2.3 From bba2181c49f1dddf8b592804a1b53cc1a3cf408a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 22 Mar 2013 10:53:40 +0100 Subject: Revert "drm/i915: set TRANSCODER_EDP even earlier" This reverts commit cc464b2a17c59adedbdc02cc54341d630354edc3. The reason is that Takashi Iwai reported a regression bisected to this commit: http://www.mail-archive.com/intel-gfx@lists.freedesktop.org/msg18788.html His machine has eDP on port D (usual desktop all-in-on setup), which intel_dp.c identifies as an eDP panel, but the hsw ddi code mishandles. Closer inspection of the code reveals that haswell_crtc_mode_set also checks intel_encoder_is_pch_edp when setting is_cpu_edp. On haswell that doesn't make much sense (since there's no edp on the pch), but what this function _really_ checks is whether that edp connector is on port A or port D. It's just that on ilk-ivb port D was on the pch ... So that explains why this seemingly innocent change killed eDP on port D. Furthermore it looks like everything else accidentally works, since we've never enabled eDP on port D support for hsw intentionally (e.g. we still register the HDMI output for port D in that case). But in retrospective I also don't like that this leaks highly platform specific details into common code, and the reason is that the drm vblank layer sucks. So instead I think we should: - move the cpu_transcoder into the dynamic pipe_config tracking (once that's merged). - fix up the drm vblank layer to finally deal with kms crtc objects instead of int pipes. v2: Pimp commit message with the better diagnosis as discussed with Paulo on irc. Cc: Paulo Zanoni Cc: Takashi Iwai Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 287b42c9d1a8..b20d50192fcc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5771,6 +5771,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } + if (is_cpu_edp) + intel_crtc->cpu_transcoder = TRANSCODER_EDP; + else + intel_crtc->cpu_transcoder = pipe; + /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); @@ -5837,11 +5842,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; int ret; - if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) - intel_crtc->cpu_transcoder = TRANSCODER_EDP; - else - intel_crtc->cpu_transcoder = pipe; - drm_vblank_pre_modeset(dev, pipe); ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, -- cgit v1.2.3 From 2124b72e6283c4e84a55e71077fee91793f4c801 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 22 Mar 2013 14:07:23 -0300 Subject: drm/i915: don't disable the power well yet We're still not 100% ready to disable the power well, so don't disable it for now. When we disable it we break the audio driver (because some of the audio registers are on the power well) and machines with eDP on port D (because it doesn't use TRANSCODER_EDP). Also, instead of just reverting the code, add a Kernel option to let us disable it if we want. This will allow us to keep developing and testing the feature while it's not enabled. This fixes problems caused by the following commit: commit d6dd9eb1d96d2b7345fe4664066c2b7ed86da898 Author: Daniel Vetter Date: Tue Jan 29 16:35:20 2013 -0200 drm/i915: dynamic Haswell display power well support References: http://www.mail-archive.com/intel-gfx@lists.freedesktop.org/msg18788.html Cc: Takashi Iwai Cc: Mengdong Lin Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0a8eceb75902..e9b57893db2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -125,6 +125,11 @@ MODULE_PARM_DESC(preliminary_hw_support, "Enable Haswell and ValleyView Support. " "(default: false)"); +int i915_disable_power_well __read_mostly = 0; +module_param_named(disable_power_well, i915_disable_power_well, int, 0600); +MODULE_PARM_DESC(disable_power_well, + "Disable the power well when possible (default: false)"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e95337c97459..01769e2a9953 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1398,6 +1398,7 @@ extern int i915_enable_fbc __read_mostly; extern bool i915_enable_hangcheck __read_mostly; extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; +extern int i915_disable_power_well __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1794c6df1bf..adca00783e61 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4079,6 +4079,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable) if (!IS_HASWELL(dev)) return; + if (!i915_disable_power_well && !enable) + return; + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE; enable_requested = tmp & HSW_PWR_WELL_ENABLE; -- cgit v1.2.3 From b1289371fcd580b4c412e6d05c4cb8ac8d277239 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 22 Mar 2013 15:44:46 +0100 Subject: Revert "drm/i915: write backlight harder" This reverts commit cf0a6584aa6d382f802f2c3cacac23ccbccde0cd. Turns out that cargo-culting breaks systems. Note that we can't revert further, since commit 770c12312ad617172b1a65b911d3e6564fc5aca8 Author: Takashi Iwai Date: Sat Aug 11 08:56:42 2012 +0200 drm/i915: Fix blank panel at reopening lid fixed a regression in 3.6-rc kernels for which we've never figured out the exact root cause. But some further inspection of the backlight code reveals that it's seriously lacking locking. And especially the asle backlight update is know to get fired (through some smm magic) when writing specific backlight control registers. So the possibility of suffering from races is rather real. Until those races are fixed I don't think it makes sense to try further hacks. Which sucks a bit, but sometimes that's how it is :( References: http://www.mail-archive.com/intel-gfx@lists.freedesktop.org/msg18788.html Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47941 Tested-by: Takashi Iwai Cc: Jani Nikula Cc: Takashi Iwai Cc: stable@vger.kernel.org (the reverted commit was cc: stable, too) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a3730e0289e5..bee8cb6108a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -321,9 +321,6 @@ void intel_panel_enable_backlight(struct drm_device *dev, if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - dev_priv->backlight_enabled = true; - intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); - if (INTEL_INFO(dev)->gen >= 4) { uint32_t reg, tmp; @@ -359,12 +356,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, } set_level: - /* Check the current backlight level and try to set again if it's zero. - * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically - * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written. + /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. + * BLC_PWM_CPU_CTL may be cleared to zero automatically when these + * registers are set. */ - if (!intel_panel_get_backlight(dev)) - intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); + dev_priv->backlight_enabled = true; + intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); } static void intel_panel_init_backlight(struct drm_device *dev) -- cgit v1.2.3 From 9979a55a833883242e3a29f3596676edd7199c46 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Mar 2013 14:38:28 +0000 Subject: net: remove a WARN_ON() in net_enable_timestamp() The WARN_ON(in_interrupt()) in net_enable_timestamp() can get false positive, in socket clone path, run from softirq context : [ 3641.624425] WARNING: at net/core/dev.c:1532 net_enable_timestamp+0x7b/0x80() [ 3641.668811] Call Trace: [ 3641.671254] [] warn_slowpath_common+0x87/0xc0 [ 3641.677871] [] warn_slowpath_null+0x1a/0x20 [ 3641.683683] [] net_enable_timestamp+0x7b/0x80 [ 3641.689668] [] sk_clone_lock+0x425/0x450 [ 3641.695222] [] inet_csk_clone_lock+0x16/0x170 [ 3641.701213] [] tcp_create_openreq_child+0x29/0x820 [ 3641.707663] [] ? ipt_do_table+0x222/0x670 [ 3641.713354] [] tcp_v4_syn_recv_sock+0xab/0x3d0 [ 3641.719425] [] tcp_check_req+0x3da/0x530 [ 3641.724979] [] ? inet_hashinfo_init+0x60/0x80 [ 3641.730964] [] ? tcp_v4_rcv+0x79f/0xbe0 [ 3641.736430] [] tcp_v4_do_rcv+0x38d/0x4f0 [ 3641.741985] [] tcp_v4_rcv+0xa7a/0xbe0 Its safe at this point because the parent socket owns a reference on the netstamp_needed, so we cant have a 0 -> 1 transition, which requires to lock a mutex. Instead of refining the check, lets remove it, as all known callers are safe. If it ever changes in the future, static_key_slow_inc() will complain anyway. Reported-by: Laurent Chavey Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index d540ced1f6c6..b13e5c766c11 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1545,7 +1545,6 @@ void net_enable_timestamp(void) return; } #endif - WARN_ON(in_interrupt()); static_key_slow_inc(&netstamp_needed); } EXPORT_SYMBOL(net_enable_timestamp); -- cgit v1.2.3 From 4a7df340ed1bac190c124c1601bfc10cde9fb4fb Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 22 Mar 2013 19:14:07 +0000 Subject: 8021q: fix a potential use-after-free vlan_vid_del() could possibly free ->vlan_info after a RCU grace period, however, we may still refer to the freed memory area by 'grp' pointer. Found by code inspection. This patch moves vlan_vid_del() as behind as possible. Cc: Patrick McHardy Cc: "David S. Miller" Signed-off-by: Cong Wang Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a18714469bf7..85addcd9372b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -86,13 +86,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) grp = &vlan_info->grp; - /* Take it out of our own structures, but be sure to interlock with - * HW accelerating devices or SW vlan input packet processing if - * VLAN is not 0 (leave it there for 802.1p). - */ - if (vlan_id) - vlan_vid_del(real_dev, vlan_id); - grp->nr_vlan_devs--; if (vlan->flags & VLAN_FLAG_MVRP) @@ -114,6 +107,13 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) vlan_gvrp_uninit_applicant(real_dev); } + /* Take it out of our own structures, but be sure to interlock with + * HW accelerating devices or SW vlan input packet processing if + * VLAN is not 0 (leave it there for 802.1p). + */ + if (vlan_id) + vlan_vid_del(real_dev, vlan_id); + /* Get rid of the vlan's reference to real_dev */ dev_put(real_dev); } -- cgit v1.2.3 From 9b46922e15f4d9d2aedcd320c3b7f7f54d956da7 Mon Sep 17 00:00:00 2001 From: Hong zhi guo Date: Sat, 23 Mar 2013 02:27:50 +0000 Subject: bridge: fix crash when set mac address of br interface When I tried to set mac address of a bridge interface to a mac address which already learned on this bridge, I got system hang. The cause is straight forward: function br_fdb_change_mac_address calls fdb_insert with NULL source nbp. Then an fdb lookup is performed. If an fdb entry is found and it's local, it's OK. But if it's not local, source is dereferenced for printk without NULL check. Signed-off-by: Hong Zhiguo Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b0812c91c0f0..bab338e6270d 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -423,7 +423,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, return 0; br_warn(br, "adding interface %s with same address " "as a received packet\n", - source->dev->name); + source ? source->dev->name : br->dev->name); fdb_delete(br, fdb); } -- cgit v1.2.3 From 8fe7f99a9e11a43183bc27420309ae105e1fec1a Mon Sep 17 00:00:00 2001 From: Kumar Amit Mehta Date: Sat, 23 Mar 2013 20:10:25 +0000 Subject: bnx2x: fix assignment of signed expression to unsigned variable fix for incorrect assignment of signed expression to unsigned variable. Signed-off-by: Kumar Amit Mehta Acked-by: Dmitry Kravkov Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 568205436a15..91ecd6a00d05 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -2139,12 +2139,12 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) break; default: BNX2X_ERR("Non valid capability ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap); @@ -2170,12 +2170,12 @@ static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num) break; default: BNX2X_ERR("Non valid TC-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } return rval; @@ -2188,7 +2188,7 @@ static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num) return -EINVAL; } -static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) +static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) { struct bnx2x *bp = netdev_priv(netdev); DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); @@ -2390,12 +2390,12 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, break; default: BNX2X_ERR("Non valid featrue-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } return rval; @@ -2431,12 +2431,12 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, break; default: BNX2X_ERR("Non valid featrue-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "dcbnl call not valid\n"); - rval = -EINVAL; + rval = 1; } return rval; -- cgit v1.2.3 From 7ebe183c6d444ef5587d803b64a1f4734b18c564 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Sun, 24 Mar 2013 10:42:25 +0000 Subject: tcp: undo spurious timeout after SACK reneging On SACK reneging the sender immediately retransmits and forces a timeout but disables Eifel (undo). If the (buggy) receiver does not drop any packet this can trigger a false slow-start retransmit storm driven by the ACKs of the original packets. This can be detected with undo and TCP timestamps. Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0d9bdacce99f..3bd55bad230a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2059,11 +2059,8 @@ void tcp_enter_loss(struct sock *sk, int how) if (tcp_is_reno(tp)) tcp_reset_reno_sack(tp); - if (!how) { - /* Push undo marker, if it was plain RTO and nothing - * was retransmitted. */ - tp->undo_marker = tp->snd_una; - } else { + tp->undo_marker = tp->snd_una; + if (how) { tp->sacked_out = 0; tp->fackets_out = 0; } -- cgit v1.2.3 From 087aa036eb79f24b856893190359ba812b460f45 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 25 Mar 2013 09:31:31 +0800 Subject: powerpc: make additional room in exception vector area The FWNMI region is fixed at 0x7000 and the vector are now overflowing that with allmodconfig. Fix that by moving slb_miss_realmode code out of that region as it doesn't need to be that close to the call sites (it is a _GLOBAL function) Fixes this build error: arch/powerpc/kernel/exceptions-64s.S: Assembler messages: arch/powerpc/kernel/exceptions-64s.S:1304: Error: attempt to move .org backwards Signed-off-by: Chen Gang Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/exceptions-64s.S | 144 +++++++++++++++++------------------ 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 200afa5bcfb7..56bd92362ce1 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1066,78 +1066,6 @@ unrecov_user_slb: #endif /* __DISABLED__ */ -/* - * r13 points to the PACA, r9 contains the saved CR, - * r12 contain the saved SRR1, SRR0 is still ready for return - * r3 has the faulting address - * r9 - r13 are saved in paca->exslb. - * r3 is saved in paca->slb_r3 - * We assume we aren't going to take any exceptions during this procedure. - */ -_GLOBAL(slb_miss_realmode) - mflr r10 -#ifdef CONFIG_RELOCATABLE - mtctr r11 -#endif - - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - - bl .slb_allocate_realmode - - /* All done -- return from exception. */ - - ld r10,PACA_EXSLB+EX_LR(r13) - ld r3,PACA_EXSLB+EX_R3(r13) - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - - mtlr r10 - - andi. r10,r12,MSR_RI /* check for unrecoverable exception */ - beq- 2f - -.machine push -.machine "power4" - mtcrf 0x80,r9 - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ -.machine pop - - RESTORE_PPR_PACA(PACA_EXSLB, r9) - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - rfid - b . /* prevent speculative execution */ - -2: mfspr r11,SPRN_SRR0 - ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10,unrecov_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - rfid - b . - -unrecov_slb: - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - DISABLE_INTS - bl .save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b 1b - - -#ifdef CONFIG_PPC_970_NAP -power4_fixup_nap: - andc r9,r9,r10 - std r9,TI_LOCAL_FLAGS(r11) - ld r10,_LINK(r1) /* make idle task do the */ - std r10,_NIP(r1) /* equivalent of a blr */ - blr -#endif - .align 7 .globl alignment_common alignment_common: @@ -1335,6 +1263,78 @@ _GLOBAL(opal_mc_secondary_handler) #endif /* CONFIG_PPC_POWERNV */ +/* + * r13 points to the PACA, r9 contains the saved CR, + * r12 contain the saved SRR1, SRR0 is still ready for return + * r3 has the faulting address + * r9 - r13 are saved in paca->exslb. + * r3 is saved in paca->slb_r3 + * We assume we aren't going to take any exceptions during this procedure. + */ +_GLOBAL(slb_miss_realmode) + mflr r10 +#ifdef CONFIG_RELOCATABLE + mtctr r11 +#endif + + stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ + std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ + + bl .slb_allocate_realmode + + /* All done -- return from exception. */ + + ld r10,PACA_EXSLB+EX_LR(r13) + ld r3,PACA_EXSLB+EX_R3(r13) + lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ + + mtlr r10 + + andi. r10,r12,MSR_RI /* check for unrecoverable exception */ + beq- 2f + +.machine push +.machine "power4" + mtcrf 0x80,r9 + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ +.machine pop + + RESTORE_PPR_PACA(PACA_EXSLB, r9) + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +2: mfspr r11,SPRN_SRR0 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10,unrecov_slb) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + rfid + b . + +unrecov_slb: + EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) + DISABLE_INTS + bl .save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b + + +#ifdef CONFIG_PPC_970_NAP +power4_fixup_nap: + andc r9,r9,r10 + std r9,TI_LOCAL_FLAGS(r11) + ld r10,_LINK(r1) /* make idle task do the */ + std r10,_NIP(r1) /* equivalent of a blr */ + blr +#endif + /* * Hash table stuff */ -- cgit v1.2.3 From 799ef90c55e692e096d8bd9e5871b95264b1e9ba Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 20 Mar 2013 22:59:11 +0100 Subject: xfrm: Fix esn sequence number diff calculation in xfrm_replay_notify_esn() Commit 0017c0b "xfrm: Fix replay notification for esn." is off by one for the sequence number wrapped case as UINT_MAX is 0xffffffff, not 0x100000000. ;) Just calculate the diff like done everywhere else in the file. Signed-off-by: Mathias Krause Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_replay.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index a3906737f49e..8dafe6d3c6e4 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -359,14 +359,12 @@ static void xfrm_replay_notify_esn(struct xfrm_state *x, int event) if (replay_esn->seq_hi == preplay_esn->seq_hi) seq_diff = replay_esn->seq - preplay_esn->seq; else - seq_diff = UINT_MAX - preplay_esn->seq - + replay_esn->seq; + seq_diff = ~preplay_esn->seq + replay_esn->seq + 1; if (replay_esn->oseq_hi == preplay_esn->oseq_hi) oseq_diff = replay_esn->oseq - preplay_esn->oseq; else - oseq_diff = UINT_MAX - preplay_esn->oseq - + replay_esn->oseq; + oseq_diff = ~preplay_esn->oseq + replay_esn->oseq + 1; if (seq_diff < x->replay_maxdiff && oseq_diff < x->replay_maxdiff) { -- cgit v1.2.3 From fa659d830df0bad8fc3a3815a7f36bd8b7ed9254 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 25 Mar 2013 11:19:12 +0800 Subject: ASoC: imx-sgtl5000: use of_node to match cpu dai Since imx-sgtl5000 is only used on DT platform, it makes more sense to use cpu_of_node rather than cpu_dai_name to match cpu dai. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 424347e9b2d7..9584e78858df 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -148,7 +148,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->dai.stream_name = "HiFi"; data->dai.codec_dai_name = "sgtl5000"; data->dai.codec_of_node = codec_np; - data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev); + data->dai.cpu_of_node = ssi_np; data->dai.platform_name = "imx-pcm-audio"; data->dai.init = &imx_sgtl5000_dai_init; data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -- cgit v1.2.3 From 3fbd45ca8d1c98f3c2582ef8bc70ade42f70947b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Mar 2013 11:51:14 +0100 Subject: mac80211: fix remain-on-channel cancel crash If a ROC item is canceled just as it expires, the work struct may be scheduled while it is running (and waiting for the mutex). This results in it being run after being freed, which obviously crashes. To fix this don't free it when aborting is requested but instead mark it as "to be freed", which makes the work a no-op and allows freeing it outside. Cc: stable@vger.kernel.org [3.6+] Reported-by: Jouni Malinen Tested-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 6 ++++-- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/offchannel.c | 23 +++++++++++++++++------ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb306814576a..a6893602f87a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2582,7 +2582,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, list_del(&dep->list); mutex_unlock(&local->mtx); - ieee80211_roc_notify_destroy(dep); + ieee80211_roc_notify_destroy(dep, true); return 0; } @@ -2622,7 +2622,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, ieee80211_start_next_roc(local); mutex_unlock(&local->mtx); - ieee80211_roc_notify_destroy(found); + ieee80211_roc_notify_destroy(found, true); } else { /* work may be pending so use it all the time */ found->abort = true; @@ -2632,6 +2632,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, /* work will clean up etc */ flush_delayed_work(&found->work); + WARN_ON(!found->to_be_freed); + kfree(found); } return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..7bdefd901f9d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -309,6 +309,7 @@ struct ieee80211_roc_work { struct ieee80211_channel *chan; bool started, abort, hw_begun, notified; + bool to_be_freed; unsigned long hw_start_time; @@ -1347,7 +1348,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local); void ieee80211_roc_setup(struct ieee80211_local *local); void ieee80211_start_next_roc(struct ieee80211_local *local); void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); -void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free); void ieee80211_sw_roc_work(struct work_struct *work); void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index cc79b4a2e821..430bd254e496 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) } } -void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free) { struct ieee80211_roc_work *dep, *tmp; + if (WARN_ON(roc->to_be_freed)) + return; + /* was never transmitted */ if (roc->frame) { cfg80211_mgmt_tx_status(&roc->sdata->wdev, @@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) GFP_KERNEL); list_for_each_entry_safe(dep, tmp, &roc->dependents, list) - ieee80211_roc_notify_destroy(dep); + ieee80211_roc_notify_destroy(dep, true); - kfree(roc); + if (free) + kfree(roc); + else + roc->to_be_freed = true; } void ieee80211_sw_roc_work(struct work_struct *work) @@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work) mutex_lock(&local->mtx); + if (roc->to_be_freed) + goto out_unlock; + if (roc->abort) goto finish; @@ -370,7 +379,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) finish: list_del(&roc->list); started = roc->started; - ieee80211_roc_notify_destroy(roc); + ieee80211_roc_notify_destroy(roc, !roc->abort); if (started) { drv_flush(local, false); @@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work) list_del(&roc->list); - ieee80211_roc_notify_destroy(roc); + ieee80211_roc_notify_destroy(roc, true); /* if there's another roc, start it now */ ieee80211_start_next_roc(local); @@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) list_for_each_entry_safe(roc, tmp, &tmp_list, list) { if (local->ops->remain_on_channel) { list_del(&roc->list); - ieee80211_roc_notify_destroy(roc); + ieee80211_roc_notify_destroy(roc, true); } else { ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); /* work will clean up etc */ flush_delayed_work(&roc->work); + WARN_ON(!roc->to_be_freed); + kfree(roc); } } -- cgit v1.2.3 From 130549fed828cc34c22624c6195afcf9e7ae56fe Mon Sep 17 00:00:00 2001 From: Gao feng Date: Thu, 21 Mar 2013 19:48:41 +0000 Subject: netfilter: reset nf_trace in nf_reset We forgot to clear the nf_trace of sk_buff in nf_reset, When we use veth device, this nf_trace information will be leaked from one net namespace to another net namespace. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- include/linux/skbuff.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 441f5bfdab8e..72b396751de7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2641,6 +2641,9 @@ static inline void nf_reset(struct sk_buff *skb) nf_bridge_put(skb->nf_bridge); skb->nf_bridge = NULL; #endif +#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) + skb->nf_trace = 0; +#endif } /* Note: This doesn't put any conntrack and bridge info in dst. */ -- cgit v1.2.3 From 558724a5b2a73ad0c7638e21e8dffc419d267b6c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 22 Mar 2013 01:28:18 +0000 Subject: netfilter: nfnetlink_queue: fix error return code in nfnetlink_queue_init() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_queue_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 1cb48540f86a..42680b2baa11 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -1062,8 +1062,10 @@ static int __init nfnetlink_queue_init(void) #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) + proc_net_netfilter, &nfqnl_file_ops)) { + status = -ENOMEM; goto cleanup_subsys; + } #endif register_netdevice_notifier(&nfqnl_dev_notifier); -- cgit v1.2.3 From deadcfc3324410726cd6a663fb4fc46be595abe7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 23 Mar 2013 16:57:59 +0100 Subject: netfilter: nfnetlink_acct: return -EINVAL if object name is empty If user-space tries to create accounting object with an empty name, then return -EINVAL. Reported-by: Michael Zintakis Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_acct.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 589d686f0b4c..dc3fd5d44464 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -49,6 +49,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, return -EINVAL; acct_name = nla_data(tb[NFACCT_NAME]); + if (strlen(acct_name) == 0) + return -EINVAL; list_for_each_entry(nfacct, &nfnl_acct_list, head) { if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0) -- cgit v1.2.3 From b563b4e3f2dd601e19b46ada31bd176fc0a16efc Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Fri, 22 Mar 2013 01:29:28 +0100 Subject: cpufreq / intel_pstate: Add function to check that all MSRs are valid Some VMs seem to try to implement some MSRs but not all the registers the driver needs. Check to make sure all the MSR that we need are available. If any of the required MSRs are not available refuse to load. References: https://bugzilla.redhat.com/show_bug.cgi?id=922923 Reported-by: Josh Stone Signed-off-by: Dirk Brandewie Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f6dd1e761129..cd9c5f4f5805 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -752,6 +752,29 @@ static struct cpufreq_driver intel_pstate_driver = { static int __initdata no_load; +static int intel_pstate_msrs_not_valid(void) +{ + /* Check that all the msr's we are using are valid. */ + u64 aperf, mperf, tmp; + + rdmsrl(MSR_IA32_APERF, aperf); + rdmsrl(MSR_IA32_MPERF, mperf); + + if (!intel_pstate_min_pstate() || + !intel_pstate_max_pstate() || + !intel_pstate_turbo_pstate()) + return -ENODEV; + + rdmsrl(MSR_IA32_APERF, tmp); + if (!(tmp - aperf)) + return -ENODEV; + + rdmsrl(MSR_IA32_MPERF, tmp); + if (!(tmp - mperf)) + return -ENODEV; + + return 0; +} static int __init intel_pstate_init(void) { int cpu, rc = 0; @@ -764,6 +787,9 @@ static int __init intel_pstate_init(void) if (!id) return -ENODEV; + if (intel_pstate_msrs_not_valid()) + return -ENODEV; + pr_info("Intel P-state driver initializing.\n"); all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus()); -- cgit v1.2.3 From e6f3eb29be471c4b536a91daab76d4aeda72a261 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Sun, 24 Mar 2013 00:54:39 +0100 Subject: cpufreq / intel_pstate: Fix calculation of current frequency Use the correct pstate value to calculate the effective frequency. References: https://bugzilla.redhat.com/show_bug.cgi?id=923942 Reported-by: Satish Balay Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index cd9c5f4f5805..b662529072f7 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -454,7 +454,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, sample->idletime_us * 100, sample->duration_us); core_pct = div64_u64(sample->aperf * 100, sample->mperf); - sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000; + sample->freq = cpu->pstate.max_pstate * core_pct * 1000; sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct), 100); -- cgit v1.2.3 From 05e99c8cf9d4e53ef6e016815db40a89a6156529 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 20 Mar 2013 14:21:10 +0000 Subject: intel-pstate: Use #defines instead of hard-coded values. They are defined in coreboot (MSR_PLATFORM) and the other one is already defined in msr-index.h. Let's use those. Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Viresh Kumar Acked-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- arch/x86/include/uapi/asm/msr-index.h | 1 + drivers/cpufreq/intel_pstate.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index 892ce40a7470..7a060f4b411f 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -44,6 +44,7 @@ #define SNB_C1_AUTO_UNDEMOTE (1UL << 27) #define SNB_C3_AUTO_UNDEMOTE (1UL << 28) +#define MSR_PLATFORM_INFO 0x000000ce #define MSR_MTRRcap 0x000000fe #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index b662529072f7..ad72922919ed 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -358,14 +358,14 @@ static void intel_pstate_sysfs_expose_params(void) static int intel_pstate_min_pstate(void) { u64 value; - rdmsrl(0xCE, value); + rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 40) & 0xFF; } static int intel_pstate_max_pstate(void) { u64 value; - rdmsrl(0xCE, value); + rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 8) & 0xFF; } @@ -373,7 +373,7 @@ static int intel_pstate_turbo_pstate(void) { u64 value; int nont, ret; - rdmsrl(0x1AD, value); + rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); nont = intel_pstate_max_pstate(); ret = ((value) & 255); if (ret <= nont) -- cgit v1.2.3 From 187da1d97f3a949b967274d7ee2f95d3a4f39251 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Fri, 22 Mar 2013 10:13:52 +0000 Subject: cpufreq: stats: do cpufreq_cpu_put() corresponding to cpufreq_cpu_get() In cpufreq_stats_free_sysfs() we aren't balancing calls to cpufreq_cpu_get() with cpufreq_cpu_put(). This will never let us have ref count to policy->kobj as zero. We will get a hang if somehow cpufreq_driver_unregister() is called. And that can happen when we compile our driver as module and insmod/rmmod it. Signed-off-by: Viresh Kumar Acked-by: Amit Kucheria Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_stats.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 2fd779eb1ed1..bfd6273fd873 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -180,15 +180,19 @@ static void cpufreq_stats_free_sysfs(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (!cpufreq_frequency_get_table(cpu)) + if (!policy) return; - if (policy && !policy_is_shared(policy)) { + if (!cpufreq_frequency_get_table(cpu)) + goto put_ref; + + if (!policy_is_shared(policy)) { pr_debug("%s: Free sysfs stat\n", __func__); sysfs_remove_group(&policy->kobj, &stats_attr_group); } - if (policy) - cpufreq_cpu_put(policy); + +put_ref: + cpufreq_cpu_put(policy); } static int cpufreq_stats_create_table(struct cpufreq_policy *policy, -- cgit v1.2.3 From aa77a52764a92216b61a6c8079b5c01937c046cd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sun, 24 Mar 2013 15:58:12 +0000 Subject: cpufreq: acpi-cpufreq: Don't set policy->related_cpus from .init() With the addition of following patch: fcf8058 cpufreq: Simplify cpufreq_add_dev() cpufreq driver's .init() routine must initialize policy->cpus with mask of all possible CPUs (Online + Offline) that share the clock. Then the core would copy this mask onto policy->related_cpus and will reset policy->cpus to carry only online cpus. acpi-cpufreq driver wasn't updated with this assumption and so sometimes when we try to hot[un]plug CPUs at run time, sysfs directories get corrupted. This patch fixes acpi-cpufreq driver against this corruption. Reported-and-tested-by: Maciej Rutecki Tested-by: Borislav Petkov Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 937bc286591f..57a8774f0b4e 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -730,7 +730,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { cpumask_copy(policy->cpus, perf->shared_cpu_map); } - cpumask_copy(policy->related_cpus, perf->shared_cpu_map); #ifdef CONFIG_SMP dmi_check_system(sw_any_bug_dmi_table); @@ -742,7 +741,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) { cpumask_clear(policy->cpus); cpumask_set_cpu(cpu, policy->cpus); - cpumask_copy(policy->related_cpus, cpu_sibling_mask(cpu)); policy->shared_type = CPUFREQ_SHARED_TYPE_HW; pr_info_once(PFX "overriding BIOS provided _PSD data\n"); } -- cgit v1.2.3 From 1166fde6a923c30f4351515b6a9a1efc513e7d00 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 25 Mar 2013 11:23:40 -0400 Subject: SUNRPC: Add barriers to ensure read ordering in rpc_wake_up_task_queue_locked We need to be careful when testing task->tk_waitqueue in rpc_wake_up_task_queue_locked, because it can be changed while we are holding the queue->lock. By adding appropriate memory barriers, we can ensure that it is safe to test task->tk_waitqueue for equality if the RPC_TASK_QUEUED bit is set. Signed-off-by: Trond Myklebust Cc: stable@vger.kernel.org --- net/sunrpc/sched.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index fb20f25ddec9..f8529fc8e542 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -180,6 +180,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); task->tk_waitqueue = queue; queue->qlen++; + /* barrier matches the read in rpc_wake_up_task_queue_locked() */ + smp_wmb(); rpc_set_queued(task); dprintk("RPC: %5u added to queue %p \"%s\"\n", @@ -430,8 +432,11 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task */ static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) { - if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue) - __rpc_do_wake_up_task(queue, task); + if (RPC_IS_QUEUED(task)) { + smp_rmb(); + if (task->tk_waitqueue == queue) + __rpc_do_wake_up_task(queue, task); + } } /* -- cgit v1.2.3 From 382a103b2b528a3085cde4ac56fc69d92a828b72 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Mar 2013 22:30:09 +0100 Subject: mac80211: fix idle handling sequence Corey Richardson reported that my idle handling cleanup (commit fd0f979a1b, "mac80211: simplify idle handling") broke ath9k_htc. The reason appears to be that it wants to go out of idle before switching channels. To fix it, reimplement that sequence. Reported-by: Corey Richardson Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 17 ++++++++++++++--- net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 78c0d90dd641..931be419ab5a 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -63,6 +63,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; + u32 changed; int err; lockdep_assert_held(&local->chanctx_mtx); @@ -76,6 +77,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local, ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; + /* acquire mutex to prevent idle from changing */ + mutex_lock(&local->mtx); + /* turn idle off *before* setting channel -- some drivers need that */ + changed = ieee80211_idle_off(local); + if (changed) + ieee80211_hw_config(local, changed); + if (!local->use_chanctx) { local->_oper_channel_type = cfg80211_get_chandef_type(chandef); @@ -85,14 +93,17 @@ ieee80211_new_chanctx(struct ieee80211_local *local, err = drv_add_chanctx(local, ctx); if (err) { kfree(ctx); - return ERR_PTR(err); + ctx = ERR_PTR(err); + + ieee80211_recalc_idle(local); + goto out; } } + /* and keep the mutex held until the new chanctx is on the list */ list_add_rcu(&ctx->list, &local->chanctx_list); - mutex_lock(&local->mtx); - ieee80211_recalc_idle(local); + out: mutex_unlock(&local->mtx); return ctx; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7bdefd901f9d..5672533a0832 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1362,6 +1362,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); +u32 ieee80211_idle_off(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, const int offset); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3bfe2612c8c2..58150f877ec3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); } -static u32 ieee80211_idle_off(struct ieee80211_local *local) +u32 ieee80211_idle_off(struct ieee80211_local *local) { if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) return 0; -- cgit v1.2.3 From 95d36075694b0431da22c3aef3d0dccdcc781344 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 21 Mar 2013 13:56:41 -0600 Subject: ASoC: tegra: add Tegra114 support to the AHUB driver Tegra114's AHUB shares a design with Tegra30, with the followin changes: * Supports more (10 vs. 4) bi-directional FIFO channels into RAM. * Requires a separate block of registers to support the above. * Supports more attached clients, i.e. new audio multiplexing and de-multiplexing modules. * Is affected by more clocks due to the above. This change fully defines the device tree binding changes required to represent these changes, and minimally extends the driver to support the new hardware, without exposing any of the new FIFO channels. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra30-ahub.txt | 26 +++++++-- sound/soc/tegra/tegra30_ahub.c | 64 ++++++++++++++++------ sound/soc/tegra/tegra30_ahub.h | 16 ++++++ 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 1ac7b1642186..0e5c12c66523 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -1,12 +1,22 @@ NVIDIA Tegra30 AHUB (Audio Hub) Required properties: -- compatible : "nvidia,tegra30-ahub" +- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc. - reg : Should contain the register physical address and length for each of - the AHUB's APBIF registers and the AHUB's own registers. + the AHUB's register blocks. + - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks. + - Tegra114 requires an additional entry, for the APBIF2 register block. - interrupts : Should contain AHUB interrupt -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for the first APBIF channel. +- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each + entry contains the Tegra DMA controller's phandle and request selector. + If a single entry is present, the request selectors for the channels are + assumed to be contiguous, and increment from this value. + If multiple values are given, one value must be given per channel. +- clocks : Must contain an entry for each required entry in clock-names. +- clock-names : Must include the following entries: + - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0, + dam1, dam2, spdif_in. + - Tegra114: Additionally requires amx, adx. - ranges : The bus address mapping for the configlink register bus. Can be empty since the mapping is 1:1. - #address-cells : For the configlink bus. Should be <1>; @@ -25,7 +35,13 @@ ahub@70080000 { reg = <0x70080000 0x200 0x70080200 0x100>; interrupts = < 0 103 0x04 >; nvidia,dma-request-selector = <&apbdma 1>; - + clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, + <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, + <&tegra_car 110>, <&tegra_car 162>; + clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif_in"; ranges; #address-cells = <1>; #size-cells = <1>; diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index e5cfb4ac41ba..4405c3a8c08c 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -287,16 +287,27 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); -static const char * const configlink_clocks[] = { - "i2s0", - "i2s1", - "i2s2", - "i2s3", - "i2s4", - "dam0", - "dam1", - "dam2", - "spdif_in", +#define CLK_LIST_MASK_TEGRA30 BIT(0) +#define CLK_LIST_MASK_TEGRA114 BIT(1) + +#define CLK_LIST_MASK_TEGRA30_OR_LATER \ + (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114) + +static const struct { + const char *clk_name; + u32 clk_list_mask; +} configlink_clocks[] = { + { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER }, + { "amx", CLK_LIST_MASK_TEGRA114 }, + { "adx", CLK_LIST_MASK_TEGRA114 }, }; #define LAST_REG(name) \ @@ -424,8 +435,24 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static struct tegra30_ahub_soc_data soc_data_tegra30 = { + .clk_list_mask = CLK_LIST_MASK_TEGRA30, +}; + +static struct tegra30_ahub_soc_data soc_data_tegra114 = { + .clk_list_mask = CLK_LIST_MASK_TEGRA114, +}; + +static const struct of_device_id tegra30_ahub_of_match[] = { + { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 }, + { .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 }, + {}, +}; + static int tegra30_ahub_probe(struct platform_device *pdev) { + const struct of_device_id *match; + const struct tegra30_ahub_soc_data *soc_data; struct clk *clk; int i; struct resource *res0, *res1, *region; @@ -436,16 +463,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev) if (ahub) return -ENODEV; + match = of_match_device(tegra30_ahub_of_match, &pdev->dev); + if (!match) + return -EINVAL; + soc_data = match->data; + /* * The AHUB hosts a register bus: the "configlink". For this to * operate correctly, all devices on this bus must be out of reset. * Ensure that here. */ for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) { - clk = clk_get(&pdev->dev, configlink_clocks[i]); + if (!(configlink_clocks[i].clk_list_mask & + soc_data->clk_list_mask)) + continue; + clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Can't get clock %s\n", - configlink_clocks[i]); + configlink_clocks[i].clk_name); ret = PTR_ERR(clk); goto err; } @@ -592,11 +627,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra30_ahub_of_match[] = { - { .compatible = "nvidia,tegra30-ahub", }, - {}, -}; - static const struct dev_pm_ops tegra30_ahub_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, tegra30_ahub_runtime_resume, NULL) diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index e690e2eecc92..7189be9e2970 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -468,7 +468,23 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); +struct tegra30_ahub_soc_data { + u32 clk_list_mask; + /* + * FIXME: There are many more differences in HW, such as: + * - More APBIF channels. + * - Extra separate chunks of register address space to represent + * the extra APBIF channels. + * - More units connected to the AHUB, so that tegra30_ahub_[rt]xcif + * need expansion, coupled with there being more defined bits in + * the AHUB routing registers. + * However, the driver doesn't support those new features yet, so we + * don't represent them here yet. + */ +}; + struct tegra30_ahub { + const struct tegra30_ahub_soc_data *soc_data; struct device *dev; struct clk *clk_d_audio; struct clk *clk_apbif; -- cgit v1.2.3 From a7fc5d256be9fda27bb69e872e6a212542a84230 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 21 Mar 2013 13:56:42 -0600 Subject: ASoC: tegra: add Tegra114 support to tegra_asoc_utils.c Tegra114 requires different PLL rates. Modify the code to know about this. On Tegra114 only for now, use regular clk_get() rather than clk_get_sys() to retrieve clocks. This assumes that the clocks will be represented in device tree. We can assure that from the start of any Tegra114 audio support. For older chips, I'll add the required clocks properties to the device trees this kernel cycle, and switch this code to only support the "new_clocks" path next cycle. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_asoc_utils.c | 30 ++++++++++++++++++++++++------ sound/soc/tegra/tegra_asoc_utils.h | 1 + 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index 49861c6ed874..24fb001be7f4 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -43,8 +43,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, case 88200: if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) new_baseclock = 56448000; - else + else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) new_baseclock = 564480000; + else + new_baseclock = 282240000; break; case 8000: case 16000: @@ -54,8 +56,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, case 96000: if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) new_baseclock = 73728000; - else + else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) new_baseclock = 552960000; + else + new_baseclock = 368640000; break; default: return -EINVAL; @@ -169,6 +173,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, struct device *dev) { int ret; + bool new_clocks = false; data->dev = dev; @@ -176,24 +181,37 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; else if (of_machine_is_compatible("nvidia,tegra30")) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; - else + else if (of_machine_is_compatible("nvidia,tegra114")) { + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114; + new_clocks = true; + } else { + dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n"); return -EINVAL; + } - data->clk_pll_a = clk_get_sys(NULL, "pll_a"); + if (new_clocks) + data->clk_pll_a = clk_get(dev, "pll_a"); + else + data->clk_pll_a = clk_get_sys(NULL, "pll_a"); if (IS_ERR(data->clk_pll_a)) { dev_err(data->dev, "Can't retrieve clk pll_a\n"); ret = PTR_ERR(data->clk_pll_a); goto err; } - data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); + if (new_clocks) + data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0"); + else + data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); if (IS_ERR(data->clk_pll_a_out0)) { dev_err(data->dev, "Can't retrieve clk pll_a_out0\n"); ret = PTR_ERR(data->clk_pll_a_out0); goto err_put_pll_a; } - if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) + if (new_clocks) + data->clk_cdev1 = clk_get(dev, "mclk"); + else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) data->clk_cdev1 = clk_get_sys(NULL, "cdev1"); else data->clk_cdev1 = clk_get_sys("extern1", NULL); diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 974c9f8830f9..19fdcafed32f 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -29,6 +29,7 @@ struct device; enum tegra_asoc_utils_soc { TEGRA_ASOC_UTILS_SOC_TEGRA20, TEGRA_ASOC_UTILS_SOC_TEGRA30, + TEGRA_ASOC_UTILS_SOC_TEGRA114, }; struct tegra_asoc_utils_data { -- cgit v1.2.3 From ded34e0fe8fe8c2d595bfa30626654e4b87621e0 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 25 Mar 2013 03:18:33 +0000 Subject: unix: fix a race condition in unix_release() As reported by Jan, and others over the past few years, there is a race condition caused by unix_release setting the sock->sk pointer to NULL before properly marking the socket as dead/orphaned. This can cause a problem with the LSM hook security_unix_may_send() if there is another socket attempting to write to this partially released socket in between when sock->sk is set to NULL and it is marked as dead/orphaned. This patch fixes this by only setting sock->sk to NULL after the socket has been marked as dead; I also take the opportunity to make unix_release_sock() a void function as it only ever returned 0/success. Dave, I think this one should go on the -stable pile. Special thanks to Jan for coming up with a reproducer for this problem. Reported-by: Jan Stancek Signed-off-by: Paul Moore Signed-off-by: David S. Miller --- net/unix/af_unix.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 51be64f163ec..f153a8d6e339 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -382,7 +382,7 @@ static void unix_sock_destructor(struct sock *sk) #endif } -static int unix_release_sock(struct sock *sk, int embrion) +static void unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); struct path path; @@ -451,8 +451,6 @@ static int unix_release_sock(struct sock *sk, int embrion) if (unix_tot_inflight) unix_gc(); /* Garbage collect fds */ - - return 0; } static void init_peercred(struct sock *sk) @@ -699,9 +697,10 @@ static int unix_release(struct socket *sock) if (!sk) return 0; + unix_release_sock(sk, 0); sock->sk = NULL; - return unix_release_sock(sk, 0); + return 0; } static int unix_autobind(struct socket *sock) -- cgit v1.2.3 From 09ce0c0c8a99651cace20958278476ee3f31678c Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 20 Mar 2013 09:30:00 +0800 Subject: usb: xhci: fix build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /home/b29397/work/code/git/linus/linux-2.6/drivers/usb/host/xhci-ring.c: In function ‘handle_port_status’: /home/b29397/work/code/git/linus/linux-2.6/drivers/usb/host/xhci-ring.c:1580: warning: ‘hcd’ may be used uninitialized in this function Signed-off-by: Peter Chen Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 882875465301..ec2681918682 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci, max_ports = HCS_MAX_PORTS(xhci->hcs_params1); if ((port_id <= 0) || (port_id > max_ports)) { xhci_warn(xhci, "Invalid port id %d\n", port_id); - bogus_port_status = true; - goto cleanup; + inc_deq(xhci, xhci->event_ring); + return; } /* Figure out which usb_hcd this port is attached to: * is it a USB 3.0 port or a USB 2.0/1.1 port? */ major_revision = xhci->port_array[port_id - 1]; + + /* Find the right roothub. */ + hcd = xhci_to_hcd(xhci); + if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) + hcd = xhci->shared_hcd; + if (major_revision == 0) { xhci_warn(xhci, "Event for port %u not in " "Extended Capabilities, ignoring.\n", @@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci, * into the index into the ports on the correct split roothub, and the * correct bus_state structure. */ - /* Find the right roothub. */ - hcd = xhci_to_hcd(xhci); - if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) - hcd = xhci->shared_hcd; bus_state = &xhci->bus_state[hcd_index(hcd)]; if (hcd->speed == HCD_USB3) port_array = xhci->usb3_ports; -- cgit v1.2.3 From 3f5eb14135ba9d97ba4b8514fc7ef5e0dac2abf4 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 19 Mar 2013 16:48:12 +0800 Subject: usb: add find_raw_port_number callback to struct hc_driver() xhci driver divides the root hub into two logical hubs which work respectively for usb 2.0 and usb 3.0 devices. They are independent devices in the usb core. But in the ACPI table, it's one device node and all usb2.0 and usb3.0 ports are under it. Binding usb port with its acpi node needs the raw port number which is reflected in the xhci extended capabilities table. This patch is to add find_raw_port_number callback to struct hc_driver(), fill it with xhci_find_raw_port_number() which will return raw port number and add a wrap usb_hcd_find_raw_port_number(). Otherwise, refactor xhci_find_real_port_number(). Using xhci_find_raw_port_number() to get real index in the HW port status registers instead of scanning through the xHCI roothub port array. This can help to speed up. All addresses in xhci->usb2_ports and xhci->usb3_ports array are kown good ports and don't include following bad ports in the extended capabilities talbe. (1) root port that doesn't have an entry (2) root port with unknown speed (3) root port that is listed twice and with different speeds. So xhci_find_raw_port_number() will only return port num of good ones and never touch bad ports above. Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp --- drivers/usb/core/hcd.c | 8 ++++++++ drivers/usb/host/xhci-mem.c | 36 ++++++++---------------------------- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci.c | 22 ++++++++++++++++++++++ drivers/usb/host/xhci.h | 1 + include/linux/usb/hcd.h | 2 ++ 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 99b34a30354f..f9ec44cbb82f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd); +int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ + if (!hcd->driver->find_raw_port_number) + return port1; + + return hcd->driver->find_raw_port_number(hcd, port1); +} + static int usb_hcd_request_irqs(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 35616ffbe3ae..6dc238c592bc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, * is attached to (or the roothub port its ancestor hub is attached to). All we * know is the index of that port under either the USB 2.0 or the USB 3.0 * roothub, but that doesn't give us the real index into the HW port status - * registers. Scan through the xHCI roothub port array, looking for the Nth - * entry of the correct port speed. Return the port number of that entry. + * registers. Call xhci_find_raw_port_number() to get real index. */ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, struct usb_device *udev) { struct usb_device *top_dev; - unsigned int num_similar_speed_ports; - unsigned int faked_port_num; - int i; + struct usb_hcd *hcd; + + if (udev->speed == USB_SPEED_SUPER) + hcd = xhci->shared_hcd; + else + hcd = xhci->main_hcd; for (top_dev = udev; top_dev->parent && top_dev->parent->parent; top_dev = top_dev->parent) /* Found device below root hub */; - faked_port_num = top_dev->portnum; - for (i = 0, num_similar_speed_ports = 0; - i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { - u8 port_speed = xhci->port_array[i]; - - /* - * Skip ports that don't have known speeds, or have duplicate - * Extended Capabilities port speed entries. - */ - if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) - continue; - /* - * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and - * 1.1 ports are under the USB 2.0 hub. If the port speed - * matches the device speed, it's a similar speed port. - */ - if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER)) - num_similar_speed_ports++; - if (num_similar_speed_ports == faked_port_num) - /* Roothub ports are numbered from 1 to N */ - return i+1; - } - return 0; + return xhci_find_raw_port_number(hcd, top_dev->portnum); } /* Setup an xHCI virtual device for a Set Address command */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index af259e0ec172..1a30c380043c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = { .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, + .find_raw_port_number = xhci_find_raw_port_number, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 849470b18831..53b8f89a0b1c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3779,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) return 0; } +/* + * Transfer the port index into real index in the HW port status + * registers. Caculate offset between the port's PORTSC register + * and port status base. Divide the number of per port register + * to get the real index. The raw port number bases 1. + */ +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + __le32 __iomem *base_addr = &xhci->op_regs->port_status_base; + __le32 __iomem *addr; + int raw_port; + + if (hcd->speed != HCD_USB3) + addr = xhci->usb2_ports[port1 - 1]; + else + addr = xhci->usb3_ports[port1 - 1]; + + raw_port = (addr - base_addr)/NUM_PORT_REGS + 1; + return raw_port; +} + #ifdef CONFIG_USB_SUSPEND /* BESL to HIRD Encoding array for USB2 LPM */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2c510e4a7d4c..d798b6931914 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1829,6 +1829,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); #ifdef CONFIG_PM int xhci_bus_suspend(struct usb_hcd *hcd); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 0a78df5f6cfd..59694b5e5e90 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -357,6 +357,7 @@ struct hc_driver { */ int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state state); + int (*find_raw_port_number)(struct usb_hcd *, int); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); @@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); +extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1); struct platform_device; extern void usb_hcd_platform_shutdown(struct platform_device *dev); -- cgit v1.2.3 From bafcaf6d84b5d1bf92dabd1ffe7753ed36b7552e Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 19 Mar 2013 16:48:13 +0800 Subject: usb/acpi: binding xhci root hub usb port with ACPI This patch is to bind xhci root hub usb port with its acpi node. The port num in the acpi table matches with the sequence in the xhci extended capabilities table. So call usb_hcd_find_raw_port_number() to transfer hub port num into raw port number which associates with the sequence in the xhci extended capabilities table before binding. Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp --- drivers/usb/core/usb-acpi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index b6f4bad3f756..255c14464bf2 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "usb.h" @@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) * connected to. */ if (!udev->parent) { - *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + int raw_port_num; + + raw_port_num = usb_hcd_find_raw_port_number(hcd, port_num); + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), + raw_port_num); if (!*handle) return -ENODEV; } else { -- cgit v1.2.3 From 1c11a172cb30492f5f6a82c6e118fdcd9946c34f Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Thu, 21 Mar 2013 12:06:48 +0530 Subject: usb: xhci: Fix TRB transfer length macro used for Event TRB. Use proper macro while extracting TRB transfer length from Transfer event TRBs. Adding a macro EVENT_TRB_LEN (bits 0:23) for the same, and use it instead of TRB_LEN (bits 0:16) in case of event TRBs. This patch should be backported to kernels as old as 2.6.31, that contain the commit b10de142119a676552df3f0d2e3a9d647036c26a "USB: xhci: Bulk transfer support". This patch will have issues applying to older kernels. Signed-off-by: Vivek gautam Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-ring.c | 24 ++++++++++++------------ drivers/usb/host/xhci.h | 4 ++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ec2681918682..9652dae95942 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2029,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) td->urb->actual_length = - td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + td->urb->transfer_buffer_length - + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); else td->urb->actual_length = 0; @@ -2062,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, /* Maybe the event was for the data stage? */ td->urb->actual_length = td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); xhci_dbg(xhci, "Waiting for status " "stage event\n"); return 0; @@ -2098,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { frame->status = 0; break; } @@ -2143,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); } len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); if (trb_comp_code != COMP_STOP_INVAL) { frame->actual_length = len; @@ -2201,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, case COMP_SUCCESS: /* Double check that the HW transferred everything. */ if (event_trb != td->last_trb || - TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { xhci_warn(xhci, "WARN Successful completion " "on short TX\n"); if (td->urb->transfer_flags & URB_SHORT_NOT_OK) @@ -2229,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, "%d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, td->urb->transfer_buffer_length, - TRB_LEN(le32_to_cpu(event->transfer_len))); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); /* Fast path - was this the last TRB in the TD for this URB? */ if (event_trb == td->last_trb) { - if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { td->urb->actual_length = td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); if (td->urb->transfer_buffer_length < td->urb->actual_length) { xhci_warn(xhci, "HC gave bad length " "of %d bytes left\n", - TRB_LEN(le32_to_cpu(event->transfer_len))); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); td->urb->actual_length = 0; if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; @@ -2282,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, if (trb_comp_code != COMP_STOP_INVAL) td->urb->actual_length += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); } return finish_td(xhci, td, event_trb, event, ep, status, false); @@ -2370,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) break; if (xhci->quirks & XHCI_TRUST_TX_LENGTH) trb_comp_code = COMP_SHORT_TX; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d798b6931914..63582719e0fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -972,6 +972,10 @@ struct xhci_transfer_event { __le32 flags; }; +/* Transfer event TRB length bit mask */ +/* bits 0:23 */ +#define EVENT_TRB_LEN(p) ((p) & 0xffffff) + /** Transfer Event bit fields **/ #define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) -- cgit v1.2.3 From a83d6755814e4614ba77e15d82796af0f695c6b8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 18 Mar 2013 10:19:51 -0700 Subject: xhci: Don't warn on empty ring for suspended devices. When a device attached to the roothub is suspended, the endpoint rings are stopped. The host may generate a completion event with the completion code set to 'Stopped' or 'Stopped Invalid' when the ring is halted. The current xHCI code prints a warning in that case, which can be really annoying if the USB device is coming into and out of suspend. Remove the unnecessary warning. Signed-off-by: Sarah Sharp Tested-by: Stephen Hemminger --- drivers/usb/host/xhci-ring.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9652dae95942..1969c001b3f9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2463,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci, * TD list. */ if (list_empty(&ep_ring->td_list)) { - xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " - "with no TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); - xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", - (le32_to_cpu(event->flags) & - TRB_TYPE_BITMASK)>>10); - xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + /* + * A stopped endpoint may generate an extra completion + * event if the device was suspended. Don't print + * warnings. + */ + if (!(trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_INVAL)) { + xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", + TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), + ep_index); + xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", + (le32_to_cpu(event->flags) & + TRB_TYPE_BITMASK)>>10); + xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + } if (ep->skip) { ep->skip = false; xhci_dbg(xhci, "td_list is empty while skip " -- cgit v1.2.3 From a79ca223e029aa4f09abb337accf1812c900a800 Mon Sep 17 00:00:00 2001 From: Hong Zhiguo Date: Tue, 26 Mar 2013 01:52:45 +0800 Subject: ipv6: fix bad free of addrconf_init_net Signed-off-by: Hong Zhiguo Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2c7e615f902..26512250e095 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4784,26 +4784,20 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) static int __net_init addrconf_init_net(struct net *net) { - int err; + int err = -ENOMEM; struct ipv6_devconf *all, *dflt; - err = -ENOMEM; - all = &ipv6_devconf; - dflt = &ipv6_devconf_dflt; + all = kmemdup(&ipv6_devconf, sizeof(ipv6_devconf), GFP_KERNEL); + if (all == NULL) + goto err_alloc_all; - if (!net_eq(net, &init_net)) { - all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); - if (all == NULL) - goto err_alloc_all; + dflt = kmemdup(&ipv6_devconf_dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); + if (dflt == NULL) + goto err_alloc_dflt; - dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); - if (dflt == NULL) - goto err_alloc_dflt; - } else { - /* these will be inherited by all namespaces */ - dflt->autoconf = ipv6_defaults.autoconf; - dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; - } + /* these will be inherited by all namespaces */ + dflt->autoconf = ipv6_defaults.autoconf; + dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; net->ipv6.devconf_all = all; net->ipv6.devconf_dflt = dflt; -- cgit v1.2.3 From d17cfb34dc5eb527b98448f3999aac52311d438b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Mar 2013 21:47:51 +0000 Subject: ARM64: early_printk: Fix check for CONFIG_ARM64_64K_PAGES The 'CONFIG_' prefix is not implicit in IS_ENABLED(). Signed-off-by: Ben Hutchings Cc: Arnd Bergmann Cc: Paul Bolle Signed-off-by: Catalin Marinas --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 224b44ab534e..70b8cd4021c4 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -261,7 +261,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt, void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt) { unsigned long size, mask; - bool page64k = IS_ENABLED(ARM64_64K_PAGES); + bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES); pgd_t *pgd; pud_t *pud; pmd_t *pmd; -- cgit v1.2.3 From 532ee00c4459086840eb35cc9c198bf580420aeb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 25 Mar 2013 12:24:35 -0300 Subject: [media] fix compilation with both V4L2 and I2C as 'm' When config options are: CONFIG_VIDEO_DEV=y CONFIG_VIDEO_V4L2=m CONFIG_I2C=m Compilation breaks, as reported by: https://bugzilla.kernel.org/show_bug.cgi?id=55681 Before changeset 7b34be71db533f3e0cf93d53cf62d036cdb5418a, no compilation errors occurred. However, the I2C code there at v4l2-device was incorrectly disabled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index a9d355230e8e..768aaf62d5dc 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -10,7 +10,7 @@ ifeq ($(CONFIG_COMPAT),y) videodev-objs += v4l2-compat-ioctl32.o endif -obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_VIDEO_V4L2) += videodev.o obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o -- cgit v1.2.3 From e4317ce877a31dbb9d96375391c1c4ad2210d637 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 22 Mar 2013 15:16:29 +0000 Subject: staging: comedi: s626: fix continuous acquisition For the s626 driver, there is a bug in the handling of asynchronous commands on the AI subdevice when the stop source is `TRIG_NONE`. The command should run continuously until cancelled, but the interrupt handler stops the command running after the first scan. The command set-up function `s626_ai_cmd()` contains this code: switch (cmd->stop_src) { case TRIG_COUNT: /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; devpriv->ai_continous = 0; break; case TRIG_NONE: /* continous acquisition */ devpriv->ai_continous = 1; devpriv->ai_sample_count = 0; break; } The interrupt handler `s626_irq_handler()` contains this code: if (!(devpriv->ai_continous)) devpriv->ai_sample_count--; if (devpriv->ai_sample_count <= 0) { devpriv->ai_cmd_running = 0; /* ... */ } So `devpriv->ai_sample_count` is only decremented for the `TRIG_COUNT` case, but `devpriv->ai_cmd_running` is set to 0 (and the command stopped) regardless. Fix this in `s626_ai_cmd()` by setting `devpriv->ai_sample_count = 1` for the `TRIG_NONE` case. The interrupt handler will not decrement it so it will remain greater than 0 and the check for stopping the acquisition will fail. Cc: stable Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/s626.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 81a1fe661579..71a73ec5af8d 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1483,7 +1483,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_NONE: /* continous acquisition */ devpriv->ai_continous = 1; - devpriv->ai_sample_count = 0; + devpriv->ai_sample_count = 1; break; } -- cgit v1.2.3 From 0f49d64c95944f5701216e900b89aab749edcda2 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 20 Mar 2013 17:56:23 -0700 Subject: mwifiex: reset skb->data after processing PCIe sleep confirm cmd respose This patch is a bug fix for an issue wherein power save was not working for PCIe. This happens because for processing power save sleep confirm command we pull skb so that skb->data points ahead of interface header. We use same skb to get other cmda responses as well. So if we don't push skb after processing cmd response, it results into reduction in skb->len and finally skb->len reaches zero. This causes failure in processing sleep command response. Fix this by pushing skb by INTF_HEADER_LEN at the end of command response processing. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/pcie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 5c395e2e6a2b..feb204613397 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1508,6 +1508,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) } memcpy(adapter->upld_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); + skb_push(skb, INTF_HEADER_LEN); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, PCI_DMA_FROMDEVICE)) return -1; -- cgit v1.2.3 From 01bdcb626f80838f55ec2af993daef50b9c59c49 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Mon, 25 Mar 2013 11:00:26 -0700 Subject: bnx2fc: Make the fcoe_cltr the SCSI host parent The fcoemon userspace daemon is searching for the a hostX under the the /sys/bus/fcoe/devices/ctlrX/ entries. When interfaces created using fcoe_sysfs and fcoe.ko this linkage is setup correctly, but bnx2fc is not doing the same thing and therefore fcoemon does not create the fcoe interface for bnx2fc. This patch sets up the correct linkage for bnx2fc such that fcoemon will work correctly with fcoe_sysfs and bnx2fc. Signed-off-by: Robert Love Acked-by: Bhanu Prakash Gollapudi --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 2daf4b0da434..cc4791cf575b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2133,6 +2133,7 @@ static int _bnx2fc_create(struct net_device *netdev, } ctlr = bnx2fc_to_ctlr(interface); + cdev = fcoe_ctlr_to_ctlr_dev(ctlr); interface->vlan_id = vlan_id; interface->timer_work_queue = @@ -2143,7 +2144,7 @@ static int _bnx2fc_create(struct net_device *netdev, goto ifput_err; } - lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0); + lport = bnx2fc_if_create(interface, &cdev->dev, 0); if (!lport) { printk(KERN_ERR PFX "Failed to create interface (%s)\n", netdev->name); @@ -2159,8 +2160,6 @@ static int _bnx2fc_create(struct net_device *netdev, /* Make this master N_port */ ctlr->lp = lport; - cdev = fcoe_ctlr_to_ctlr_dev(ctlr); - if (link_state == BNX2FC_CREATE_LINK_UP) cdev->enabled = FCOE_CTLR_ENABLED; else -- cgit v1.2.3 From 85ecd0322b9a1a9f451d9150e9460ab42fd17219 Mon Sep 17 00:00:00 2001 From: Soeren Moch Date: Fri, 22 Mar 2013 12:16:52 -0400 Subject: USB: EHCI: fix bug in iTD/siTD DMA pool allocation [Description written by Alan Stern] Soeren tracked down a very difficult bug in ehci-hcd's DMA pool management of iTD and siTD structures. Some background: ehci-hcd gives each isochronous endpoint its own set of active and free itd's (or sitd's for full-speed devices). When a new itd is needed, it is taken from the head of the free list, if possible. However, itd's must not be used twice in a single frame because the hardware continues to access the data structure for the entire duration of a frame. Therefore if the itd at the head of the free list has its "frame" member equal to the current value of ehci->now_frame, it cannot be reused and instead a new itd is allocated from the DMA pool. The entries on the free list are not released back to the pool until the endpoint is no longer in use. The bug arises from the fact that sometimes an itd can be moved back onto the free list before itd->frame has been set properly. In Soeren's case, this happened because ehci-hcd can allocate one more itd than it actually needs for an URB; the extra itd may or may not be required depending on how the transfer aligns with a frame boundary. For example, an URB with 8 isochronous packets will cause two itd's to be allocated. If the URB is scheduled to start in microframe 3 of frame N then it will require both itds: one for microframes 3 - 7 of frame N and one for microframes 0 - 2 of frame N+1. But if the URB had been scheduled to start in microframe 0 then it would require only the first itd, which could cover microframes 0 - 7 of frame N. The second itd would be returned to the end of the free list. The itd allocation routine initializes the entire structure to 0, so the extra itd ends up on the free list with itd->frame set to 0 instead of a meaningful value. After a while the itd reaches the head of the list, and occasionally this happens when ehci->now_frame is equal to 0. Then, even though it would be okay to reuse this itd, the driver thinks it must get another itd from the DMA pool. For as long as the isochronous endpoint remains in use, this flaw in the mechanism causes more and more itd's to be taken slowly from the DMA pool. Since none are released back, the pool eventually becomes exhausted. This reuslts in memory allocation failures, which typically show up during a long-running audio stream. Video might suffer the same effect. The fix is very simple. To prevent allocations from the pool when they aren't needed, make sure that itd's sent back to the free list prematurely have itd->frame set to an invalid value which can never be equal to ehci->now_frame. This should be applied to -stable kernels going back to 3.6. Signed-off-by: Soeren Moch Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index b476daf49f6f..010f686d8881 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1214,6 +1214,7 @@ itd_urb_transaction ( memset (itd, 0, sizeof *itd); itd->itd_dma = itd_dma; + itd->frame = 9999; /* an invalid value */ list_add (&itd->itd_list, &sched->td_list); } spin_unlock_irqrestore (&ehci->lock, flags); @@ -1915,6 +1916,7 @@ sitd_urb_transaction ( memset (sitd, 0, sizeof *sitd); sitd->sitd_dma = sitd_dma; + sitd->frame = 9999; /* an invalid value */ list_add (&sitd->sitd_list, &iso_sched->td_list); } -- cgit v1.2.3 From f9294e989fa6f2990da155242db03cea1550cac8 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Fri, 22 Mar 2013 09:12:13 +0000 Subject: powerpc: define the conditions where the ePAPR idle hcall can be supported For 32-bit, CONFIG_EPAPR_PARAVIRT pulls in both epapr_paravirt.c and epapr_hcalls.c which contains the 32-bit paravirt idle loop. For 64-bit, the paravirt idle loop is in idle_book3e.S and that source file is included only if CONFIG_PPC_BOOK3E_64 defined. This patch makes that dependency for 64-bit explicit. Fixes these build errors: arch/powerpc/kernel/built-in.o: In function `restore_pblist_ptr': ftrace.c:(.toc+0xdc0): undefined reference to `epapr_ev_idle_start' ftrace.c:(.toc+0xdd0): undefined reference to `epapr_ev_idle' Signed-off-by: Stuart Yoder Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/epapr_paravirt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c index f3eab8594d9f..d44a571e45a7 100644 --- a/arch/powerpc/kernel/epapr_paravirt.c +++ b/arch/powerpc/kernel/epapr_paravirt.c @@ -23,8 +23,10 @@ #include #include +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) extern void epapr_ev_idle(void); extern u32 epapr_ev_idle_start[]; +#endif bool epapr_paravirt_enabled; @@ -47,11 +49,15 @@ static int __init epapr_paravirt_init(void) for (i = 0; i < (len / 4); i++) { patch_instruction(epapr_hypercall_start + i, insts[i]); +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) patch_instruction(epapr_ev_idle_start + i, insts[i]); +#endif } +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) if (of_get_property(hyper_node, "has-idle", NULL)) ppc_md.power_save = epapr_ev_idle; +#endif epapr_paravirt_enabled = true; -- cgit v1.2.3 From f9c4358edb285cead00a0d6cf0644c84ee773026 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Mon, 25 Mar 2013 11:00:27 -0700 Subject: fcoe: Fix deadlock between create and destroy paths We can deadlock (s_active and fcoe_config_mutex) if a port is being destroyed at the same time one is being created. [ 4200.503113] ====================================================== [ 4200.503114] [ INFO: possible circular locking dependency detected ] [ 4200.503116] 3.8.0-rc5+ #8 Not tainted [ 4200.503117] ------------------------------------------------------- [ 4200.503118] kworker/3:2/2492 is trying to acquire lock: [ 4200.503119] (s_active#292){++++.+}, at: [] sysfs_addrm_finish+0x3b/0x70 [ 4200.503127] but task is already holding lock: [ 4200.503128] (fcoe_config_mutex){+.+.+.}, at: [] fcoe_destroy_work+0xe8/0x120 [fcoe] [ 4200.503133] which lock already depends on the new lock. [ 4200.503135] the existing dependency chain (in reverse order) is: [ 4200.503136] -> #1 (fcoe_config_mutex){+.+.+.}: [ 4200.503139] [] lock_acquire+0xa1/0x140 [ 4200.503143] [] mutex_lock_nested+0x6e/0x360 [ 4200.503146] [] fcoe_enable+0x1d/0xb0 [fcoe] [ 4200.503148] [] fcoe_ctlr_enabled+0x2d/0x50 [fcoe] [ 4200.503151] [] store_ctlr_enabled+0x38/0x90 [libfcoe] [ 4200.503154] [] dev_attr_store+0x18/0x30 [ 4200.503157] [] sysfs_write_file+0xe0/0x150 [ 4200.503160] [] vfs_write+0xac/0x180 [ 4200.503162] [] sys_write+0x52/0xa0 [ 4200.503164] [] system_call_fastpath+0x16/0x1b [ 4200.503167] -> #0 (s_active#292){++++.+}: [ 4200.503170] [] __lock_acquire+0x135f/0x1c90 [ 4200.503172] [] lock_acquire+0xa1/0x140 [ 4200.503174] [] sysfs_deactivate+0x116/0x160 [ 4200.503176] [] sysfs_addrm_finish+0x3b/0x70 [ 4200.503178] [] sysfs_hash_and_remove+0x5b/0xb0 [ 4200.503180] [] sysfs_remove_group+0x61/0x100 [ 4200.503183] [] device_remove_groups+0x3b/0x60 [ 4200.503185] [] device_remove_attrs+0x44/0x80 [ 4200.503187] [] device_del+0x127/0x1c0 [ 4200.503189] [] device_unregister+0x22/0x60 [ 4200.503191] [] fcoe_ctlr_device_delete+0xe0/0xf0 [libfcoe] [ 4200.503194] [] fcoe_interface_cleanup+0x6c/0xa0 [fcoe] [ 4200.503196] [] fcoe_destroy_work+0x105/0x120 [fcoe] [ 4200.503198] [] process_one_work+0x1a1/0x580 [ 4200.503203] [] worker_thread+0x15e/0x440 [ 4200.503205] [] kthread+0xea/0xf0 [ 4200.503207] [] ret_from_fork+0x7c/0xb0 [ 4200.503209] other info that might help us debug this: [ 4200.503211] Possible unsafe locking scenario: [ 4200.503212] CPU0 CPU1 [ 4200.503213] ---- ---- [ 4200.503214] lock(fcoe_config_mutex); [ 4200.503215] lock(s_active#292); [ 4200.503218] lock(fcoe_config_mutex); [ 4200.503219] lock(s_active#292); [ 4200.503221] *** DEADLOCK *** [ 4200.503223] 3 locks held by kworker/3:2/2492: [ 4200.503224] #0: (fcoe){.+.+.+}, at: [] process_one_work+0x13b/0x580 [ 4200.503228] #1: ((&port->destroy_work)){+.+.+.}, at: [] process_one_work+0x13b/0x580 [ 4200.503232] #2: (fcoe_config_mutex){+.+.+.}, at: [] fcoe_destroy_work+0xe8/0x120 [fcoe] [ 4200.503236] stack backtrace: [ 4200.503238] Pid: 2492, comm: kworker/3:2 Not tainted 3.8.0-rc5+ #8 [ 4200.503240] Call Trace: [ 4200.503243] [] print_circular_bug+0x1fb/0x20c [ 4200.503246] [] __lock_acquire+0x135f/0x1c90 [ 4200.503248] [] ? debug_check_no_locks_freed+0x9a/0x180 [ 4200.503250] [] lock_acquire+0xa1/0x140 [ 4200.503253] [] ? sysfs_addrm_finish+0x3b/0x70 [ 4200.503255] [] sysfs_deactivate+0x116/0x160 [ 4200.503258] [] ? sysfs_addrm_finish+0x3b/0x70 [ 4200.503260] [] sysfs_addrm_finish+0x3b/0x70 [ 4200.503262] [] sysfs_hash_and_remove+0x5b/0xb0 [ 4200.503265] [] sysfs_remove_group+0x61/0x100 [ 4200.503273] [] device_remove_groups+0x3b/0x60 [ 4200.503275] [] device_remove_attrs+0x44/0x80 [ 4200.503277] [] device_del+0x127/0x1c0 [ 4200.503279] [] device_unregister+0x22/0x60 [ 4200.503282] [] fcoe_ctlr_device_delete+0xe0/0xf0 [libfcoe] [ 4200.503285] [] fcoe_interface_cleanup+0x6c/0xa0 [fcoe] [ 4200.503287] [] fcoe_destroy_work+0x105/0x120 [fcoe] [ 4200.503290] [] process_one_work+0x1a1/0x580 [ 4200.503292] [] ? process_one_work+0x13b/0x580 [ 4200.503295] [] ? fcoe_if_destroy+0x230/0x230 [fcoe] [ 4200.503297] [] worker_thread+0x15e/0x440 [ 4200.503299] [] ? busy_worker_rebind_fn+0x100/0x100 [ 4200.503301] [] kthread+0xea/0xf0 [ 4200.503304] [] ? kthread_create_on_node+0x160/0x160 [ 4200.503306] [] ret_from_fork+0x7c/0xb0 [ 4200.503308] [] ? kthread_create_on_node+0x160/0x160 Signed-off-by: Robert Love Tested-by: Jack Morgan --- drivers/scsi/fcoe/fcoe.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index b5d92fc93c70..9bfdc9a3f897 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -490,7 +490,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); rtnl_lock(); if (!fcoe->removed) @@ -501,7 +500,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) /* tear-down the FCoE controller */ fcoe_ctlr_destroy(fip); scsi_host_put(fip->lp->host); - fcoe_ctlr_device_delete(ctlr_dev); dev_put(netdev); module_put(THIS_MODULE); } @@ -2194,6 +2192,8 @@ out_nodev: */ static void fcoe_destroy_work(struct work_struct *work) { + struct fcoe_ctlr_device *cdev; + struct fcoe_ctlr *ctlr; struct fcoe_port *port; struct fcoe_interface *fcoe; struct Scsi_Host *shost; @@ -2224,10 +2224,15 @@ static void fcoe_destroy_work(struct work_struct *work) mutex_lock(&fcoe_config_mutex); fcoe = port->priv; + ctlr = fcoe_to_ctlr(fcoe); + cdev = fcoe_ctlr_to_ctlr_dev(ctlr); + fcoe_if_destroy(port->lport); fcoe_interface_cleanup(fcoe); mutex_unlock(&fcoe_config_mutex); + + fcoe_ctlr_device_delete(cdev); } /** @@ -2335,7 +2340,9 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode, rc = -EIO; rtnl_unlock(); fcoe_interface_cleanup(fcoe); - goto out_nortnl; + mutex_unlock(&fcoe_config_mutex); + fcoe_ctlr_device_delete(ctlr_dev); + goto out; } /* Make this the "master" N_Port */ @@ -2375,8 +2382,8 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode, out_nodev: rtnl_unlock(); -out_nortnl: mutex_unlock(&fcoe_config_mutex); +out: return rc; } -- cgit v1.2.3 From 8a9a71381208b2364a2d12b0d257ae333917a1bc Mon Sep 17 00:00:00 2001 From: Robert Love Date: Mon, 25 Mar 2013 11:00:27 -0700 Subject: libfc, fcoe, bnx2fc: Always use fcoe_disc_init for discovery layer initialization Currently libfcoe is doing some libfc discovery layer initialization outside of libfc. This patch moves this code into libfc and sets up a split in discovery (one time) initialization code and (re-configurable) settings that will come in the next patch. Signed-off-by: Robert Love Tested-by: Jack Morgan Reviewed-by: Bhanu Prakash Gollapudi --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2 +- drivers/scsi/fcoe/fcoe_ctlr.c | 11 ++++++----- drivers/scsi/libfc/fc_disc.c | 5 +++-- include/scsi/libfc.h | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index cc4791cf575b..b867b1bfa908 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -939,7 +939,7 @@ static int bnx2fc_libfc_config(struct fc_lport *lport) fc_elsct_init(lport); fc_exch_init(lport); fc_rport_init(lport); - fc_disc_init(lport); + fc_disc_init(lport, lport); return 0; } diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 08c3bc398da2..ba2f977a6e1d 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2826,6 +2826,8 @@ unlock: int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, const struct libfc_function_template *tt, int init_fcp) { + void *priv = lport; + /* Set the function pointers set by the LLDD */ memcpy(&lport->tt, tt, sizeof(*tt)); if (init_fcp && fc_fcp_init(lport)) @@ -2842,12 +2844,11 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, lport->tt.disc_start = fcoe_ctlr_disc_start; lport->tt.disc_stop = fcoe_ctlr_disc_stop; lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final; - mutex_init(&lport->disc.disc_mutex); - INIT_LIST_HEAD(&lport->disc.rports); - lport->disc.priv = fip; - } else { - fc_disc_init(lport); + priv = fip; } + + fc_disc_init(lport, priv); + return 0; } EXPORT_SYMBOL_GPL(fcoe_libfc_config); diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 8e561e6a557c..141c54b97082 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -714,8 +714,9 @@ static void fc_disc_stop_final(struct fc_lport *lport) /** * fc_disc_init() - Initialize the discovery layer for a local port * @lport: The local port that needs the discovery layer to be initialized + * @priv: Private data structre for users of the discovery layer */ -int fc_disc_init(struct fc_lport *lport) +int fc_disc_init(struct fc_lport *lport, void *priv) { struct fc_disc *disc; @@ -736,7 +737,7 @@ int fc_disc_init(struct fc_lport *lport) mutex_init(&disc->disc_mutex); INIT_LIST_HEAD(&disc->rports); - disc->priv = lport; + disc->priv = priv; return 0; } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 399162b50a8d..add2a498bd44 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1074,7 +1074,7 @@ void fc_rport_terminate_io(struct fc_rport *); /* * DISCOVERY LAYER *****************************/ -int fc_disc_init(struct fc_lport *); +int fc_disc_init(struct fc_lport *, void *); static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc) { -- cgit v1.2.3 From 0807619d3c64d935c257a377ac86982c777f969c Mon Sep 17 00:00:00 2001 From: Robert Love Date: Mon, 25 Mar 2013 11:00:28 -0700 Subject: libfc, fcoe, bnx2fc: Split fc_disc_init into fc_disc_{init, config} Split discovery initialization in code that is setup once (fcoe_disc_init) and code that can be re-configured (fcoe_disc_config). Signed-off-by: Robert Love Tested-by: Jack Morgan Reviewed-by: Bhanu Prakash Gollapudi --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 3 ++- drivers/scsi/fcoe/fcoe_ctlr.c | 3 ++- drivers/scsi/libfc/fc_disc.c | 25 +++++++++++++++++-------- include/scsi/libfc.h | 3 ++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index b867b1bfa908..90bc7bd00966 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -939,7 +939,8 @@ static int bnx2fc_libfc_config(struct fc_lport *lport) fc_elsct_init(lport); fc_exch_init(lport); fc_rport_init(lport); - fc_disc_init(lport, lport); + fc_disc_init(lport); + fc_disc_config(lport, lport); return 0; } diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index ba2f977a6e1d..34ee56cf4bcc 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2847,7 +2847,8 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, priv = fip; } - fc_disc_init(lport, priv); + fc_disc_init(lport); + fc_disc_config(lport, priv); return 0; } diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 141c54b97082..880a9068ca12 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -712,13 +712,13 @@ static void fc_disc_stop_final(struct fc_lport *lport) } /** - * fc_disc_init() - Initialize the discovery layer for a local port - * @lport: The local port that needs the discovery layer to be initialized + * fc_disc_config() - Configure the discovery layer for a local port + * @lport: The local port that needs the discovery layer to be configured * @priv: Private data structre for users of the discovery layer */ -int fc_disc_init(struct fc_lport *lport, void *priv) +void fc_disc_config(struct fc_lport *lport, void *priv) { - struct fc_disc *disc; + struct fc_disc *disc = &lport->disc; if (!lport->tt.disc_start) lport->tt.disc_start = fc_disc_start; @@ -733,12 +733,21 @@ int fc_disc_init(struct fc_lport *lport, void *priv) lport->tt.disc_recv_req = fc_disc_recv_req; disc = &lport->disc; - INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); - mutex_init(&disc->disc_mutex); - INIT_LIST_HEAD(&disc->rports); disc->priv = priv; +} +EXPORT_SYMBOL(fc_disc_config); - return 0; +/** + * fc_disc_init() - Initialize the discovery layer for a local port + * @lport: The local port that needs the discovery layer to be initialized + */ +void fc_disc_init(struct fc_lport *lport) +{ + struct fc_disc *disc = &lport->disc; + + INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); + mutex_init(&disc->disc_mutex); + INIT_LIST_HEAD(&disc->rports); } EXPORT_SYMBOL(fc_disc_init); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index add2a498bd44..e1379b4e8faf 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1074,7 +1074,8 @@ void fc_rport_terminate_io(struct fc_rport *); /* * DISCOVERY LAYER *****************************/ -int fc_disc_init(struct fc_lport *, void *); +void fc_disc_init(struct fc_lport *); +void fc_disc_config(struct fc_lport *, void *); static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc) { -- cgit v1.2.3 From 0db0e377ab5be5d507a2fca3d78215cd2e83b974 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Mon, 25 Mar 2013 11:00:28 -0700 Subject: libfcoe: Fix fcoe_sysfs VN2VN mode The libfc discovery layer is being initialized in the 'create' paths for both legacy libfcoe module parameters and fcoe_sysfs control interfaces. The problem is that for VN2VN mode the discovery layer is initialized as if it were in 'fabric' mode and it is not re-configured when the mode is changed to 'vn2vn'. This patch splits out code that needs to be initialized once and code that can, and should be, re-configured when the mode changes. Additionally this patch makes that change so that the discovery layer can be reconfigured to the libfcoe implementation when in 'vn2vn' mode. Signed-off-by: Robert Love Tested-by: Jack Morgan Reviewed-by: Bhanu Prakash Gollapudi --- drivers/scsi/fcoe/fcoe_ctlr.c | 60 ++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 34ee56cf4bcc..a76247201be5 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2814,6 +2814,47 @@ unlock: fc_lport_set_local_id(fip->lp, new_port_id); } +/** + * fcoe_ctlr_mode_set() - Set or reset the ctlr's mode + * @lport: The local port to be (re)configured + * @fip: The FCoE controller whose mode is changing + * @fip_mode: The new fip mode + * + * Note that the we shouldn't be changing the libfc discovery settings + * (fc_disc_config) while an lport is going through the libfc state + * machine. The mode can only be changed when a fcoe_ctlr device is + * disabled, so that should ensure that this routine is only called + * when nothing is happening. + */ +void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip, + enum fip_state fip_mode) +{ + void *priv; + + WARN_ON(lport->state != LPORT_ST_RESET && + lport->state != LPORT_ST_DISABLED); + + if (fip_mode == FIP_MODE_VN2VN) { + lport->rport_priv_size = sizeof(struct fcoe_rport); + lport->point_to_multipoint = 1; + lport->tt.disc_recv_req = fcoe_ctlr_disc_recv; + lport->tt.disc_start = fcoe_ctlr_disc_start; + lport->tt.disc_stop = fcoe_ctlr_disc_stop; + lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final; + priv = fip; + } else { + lport->rport_priv_size = 0; + lport->point_to_multipoint = 0; + lport->tt.disc_recv_req = NULL; + lport->tt.disc_start = NULL; + lport->tt.disc_stop = NULL; + lport->tt.disc_stop_final = NULL; + priv = lport; + } + + fc_disc_config(lport, priv); +} + /** * fcoe_libfc_config() - Sets up libfc related properties for local port * @lport: The local port to configure libfc for @@ -2826,8 +2867,6 @@ unlock: int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, const struct libfc_function_template *tt, int init_fcp) { - void *priv = lport; - /* Set the function pointers set by the LLDD */ memcpy(&lport->tt, tt, sizeof(*tt)); if (init_fcp && fc_fcp_init(lport)) @@ -2835,21 +2874,9 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, fc_exch_init(lport); fc_elsct_init(lport); fc_lport_init(lport); - if (fip->mode == FIP_MODE_VN2VN) - lport->rport_priv_size = sizeof(struct fcoe_rport); fc_rport_init(lport); - if (fip->mode == FIP_MODE_VN2VN) { - lport->point_to_multipoint = 1; - lport->tt.disc_recv_req = fcoe_ctlr_disc_recv; - lport->tt.disc_start = fcoe_ctlr_disc_start; - lport->tt.disc_stop = fcoe_ctlr_disc_stop; - lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final; - priv = fip; - } - fc_disc_init(lport); - fc_disc_config(lport, priv); - + fcoe_ctlr_mode_set(lport, fip, fip->mode); return 0; } EXPORT_SYMBOL_GPL(fcoe_libfc_config); @@ -2877,6 +2904,7 @@ EXPORT_SYMBOL(fcoe_fcf_get_selected); void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev) { struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); + struct fc_lport *lport = ctlr->lp; mutex_lock(&ctlr->ctlr_mutex); switch (ctlr_dev->mode) { @@ -2890,5 +2918,7 @@ void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev) } mutex_unlock(&ctlr->ctlr_mutex); + + fcoe_ctlr_mode_set(lport, ctlr, ctlr->mode); } EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode); -- cgit v1.2.3 From 9196d8acd7f91758872108958dfded7684628444 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 19 Mar 2013 11:34:56 +0100 Subject: TTY: 8250, revert module name change In 3.7 the 8250 module name was changed unintentionally from 8250 to 8250_core by commit 835d844d1a28efba81d5aca7385e24c29d3a6db2 (8250_pnp: do pnp probe before legacy probe). We then had to re-introduce the old module options to ensure the old good 8250.nr_uart & co. still work. This can be done only by a very dirty hack and we did it in f2b8dfd9e480c3db3bad0c25c590a5d11b31f4ef (serial: 8250: Keep 8250. module options functional after driver rename). That is so damn ugly so that I decided to revert to the old module name and deprecate the new 8250_core options present in 3.7 and 3.8 only. The deprecation will happen in the following patch. Note that this patch changes the hack above to support "8250_core.*", because we now have "8250.*" natively. Signed-off-by: Jiri Slaby Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.c | 3448 ----------------------------------- drivers/tty/serial/8250/8250_core.c | 3448 +++++++++++++++++++++++++++++++++++ drivers/tty/serial/8250/Makefile | 8 +- 3 files changed, 3452 insertions(+), 3452 deletions(-) delete mode 100644 drivers/tty/serial/8250/8250.c create mode 100644 drivers/tty/serial/8250/8250_core.c diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c deleted file mode 100644 index cf6a5383748a..000000000000 --- a/drivers/tty/serial/8250/8250.c +++ /dev/null @@ -1,3448 +0,0 @@ -/* - * Driver for 8250/16550-type serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2001 Russell King. - * - * 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. - * - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. - * membase is an 'ioremapped' cookie. - */ - -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SPARC -#include -#endif - -#include -#include - -#include "8250.h" - -/* - * Configuration: - * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option - * is unsafe when used on edge-triggered interrupts. - */ -static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; - -static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; - -static struct uart_driver serial8250_reg; - -static int serial_index(struct uart_port *port) -{ - return (serial8250_reg.minor - 64) + port->line; -} - -static unsigned int skip_txen_test; /* force skip of txen test at init time */ - -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -#define PASS_LIMIT 512 - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - - -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define CONFIG_SERIAL_DETECT_IRQ 1 -#endif -#ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS 1 -#endif - -/* - * HUB6 is always on. This will be removed once the header - * files have been cleaned. - */ -#define CONFIG_HUB6 1 - -#include -/* - * SERIAL_PORT_DFNS tells us about built-in ports that have no - * standard enumeration mechanism. Platforms that can find all - * serial ports via mechanisms like ACPI or PCI need not supply it. - */ -#ifndef SERIAL_PORT_DFNS -#define SERIAL_PORT_DFNS -#endif - -static const struct old_serial_port old_serial_port[] = { - SERIAL_PORT_DFNS /* defined in asm/serial.h */ -}; - -#define UART_NR CONFIG_SERIAL_8250_NR_UARTS - -#ifdef CONFIG_SERIAL_8250_RSA - -#define PORT_RSA_MAX 4 -static unsigned long probe_rsa[PORT_RSA_MAX]; -static unsigned int probe_rsa_count; -#endif /* CONFIG_SERIAL_8250_RSA */ - -struct irq_info { - struct hlist_node node; - int irq; - spinlock_t lock; /* Protects list not the hash */ - struct list_head *head; -}; - -#define NR_IRQ_HASH 32 /* Can be adjusted later */ -static struct hlist_head irq_lists[NR_IRQ_HASH]; -static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ - -/* - * Here we define the default xmit fifo size used for each type of UART. - */ -static const struct serial8250_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_8250] = { - .name = "8250", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16450] = { - .name = "16450", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550] = { - .name = "16550", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550A] = { - .name = "16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_CIRRUS] = { - .name = "Cirrus", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16650] = { - .name = "ST16650", - .fifo_size = 1, - .tx_loadsz = 1, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16650V2] = { - .name = "ST16650V2", - .fifo_size = 32, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16750] = { - .name = "TI16750", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, - }, - [PORT_STARTECH] = { - .name = "Startech", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16C950] = { - .name = "16C950/954", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - /* UART_CAP_EFR breaks billionon CF bluetooth card. */ - .flags = UART_CAP_FIFO | UART_CAP_SLEEP, - }, - [PORT_16654] = { - .name = "ST16654", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16850] = { - .name = "XR16850", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_RSA] = { - .name = "RSA", - .fifo_size = 2048, - .tx_loadsz = 2048, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, - .flags = UART_CAP_FIFO, - }, - [PORT_NS16550A] = { - .name = "NS16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_NATSEMI, - }, - [PORT_XSCALE] = { - .name = "XScale", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, - }, - [PORT_OCTEON] = { - .name = "OCTEON", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_AR7] = { - .name = "AR7", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_U6_16550A] = { - .name = "U6_16550A", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_TEGRA] = { - .name = "Tegra", - .fifo_size = 32, - .tx_loadsz = 8, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_01, - .flags = UART_CAP_FIFO | UART_CAP_RTOIE, - }, - [PORT_XR17D15X] = { - .name = "XR17D15X", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_XR17V35X] = { - .name = "XR17V35X", - .fifo_size = 256, - .tx_loadsz = 256, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | - UART_FCR_T_TRIG_11, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_LPC3220] = { - .name = "LPC3220", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | - UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, - .flags = UART_CAP_FIFO, - }, - [PORT_BRCM_TRUMANAGE] = { - .name = "TruManage", - .fifo_size = 1, - .tx_loadsz = 1024, - .flags = UART_CAP_HFIFO, - }, - [PORT_8250_CIR] = { - .name = "CIR port" - }, - [PORT_ALTR_16550_F32] = { - .name = "Altera 16550 FIFO32", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F64] = { - .name = "Altera 16550 FIFO64", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F128] = { - .name = "Altera 16550 FIFO128", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, -}; - -/* Uart divisor latch read */ -static int default_serial_dl_read(struct uart_8250_port *up) -{ - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static void default_serial_dl_write(struct uart_8250_port *up, int value) -{ - serial_out(up, UART_DLL, value & 0xff); - serial_out(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - -/* Au1x00/RT288x UART hardware has a weird register layout */ -static const u8 au_io_in_map[] = { - [UART_RX] = 0, - [UART_IER] = 2, - [UART_IIR] = 3, - [UART_LCR] = 5, - [UART_MCR] = 6, - [UART_LSR] = 7, - [UART_MSR] = 8, -}; - -static const u8 au_io_out_map[] = { - [UART_TX] = 1, - [UART_IER] = 2, - [UART_FCR] = 4, - [UART_LCR] = 5, - [UART_MCR] = 6, -}; - -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - offset = au_io_in_map[offset] << p->regshift; - return __raw_readl(p->membase + offset); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - offset = au_io_out_map[offset] << p->regshift; - __raw_writel(value, p->membase + offset); -} - -/* Au1x00 haven't got a standard divisor latch */ -static int au_serial_dl_read(struct uart_8250_port *up) -{ - return __raw_readl(up->port.membase + 0x28); -} - -static void au_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x28); -} - -#endif - -static unsigned int hub6_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - return inb(p->iobase + 1); -} - -static void hub6_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - outb(value, p->iobase + 1); -} - -static unsigned int mem_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readb(p->membase + offset); -} - -static void mem_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writeb(value, p->membase + offset); -} - -static void mem32_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writel(value, p->membase + offset); -} - -static unsigned int mem32_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readl(p->membase + offset); -} - -static unsigned int io_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return inb(p->iobase + offset); -} - -static void io_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(value, p->iobase + offset); -} - -static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); - -static void set_io_from_upio(struct uart_port *p) -{ - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); - - up->dl_read = default_serial_dl_read; - up->dl_write = default_serial_dl_write; - - switch (p->iotype) { - case UPIO_HUB6: - p->serial_in = hub6_serial_in; - p->serial_out = hub6_serial_out; - break; - - case UPIO_MEM: - p->serial_in = mem_serial_in; - p->serial_out = mem_serial_out; - break; - - case UPIO_MEM32: - p->serial_in = mem32_serial_in; - p->serial_out = mem32_serial_out; - break; - -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; - up->dl_read = au_serial_dl_read; - up->dl_write = au_serial_dl_write; - break; -#endif - - default: - p->serial_in = io_serial_in; - p->serial_out = io_serial_out; - break; - } - /* Remember loaded iotype */ - up->cur_iotype = p->iotype; - p->handle_irq = serial8250_default_handle_irq; -} - -static void -serial_port_out_sync(struct uart_port *p, int offset, int value) -{ - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_AU: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: - p->serial_out(p, offset, value); - } -} - -/* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} - -/* - * FIFO support. - */ -static void serial8250_clear_fifos(struct uart_8250_port *p) -{ - if (p->capabilities & UART_CAP_FIFO) { - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(p, UART_FCR, 0); - } -} - -void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) -{ - unsigned char fcr; - - serial8250_clear_fifos(p); - fcr = uart_config[p->port.type].fcr; - serial_out(p, UART_FCR, fcr); -} -EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); - -/* - * IER sleep support. UARTs which have EFRs need the "extended - * capability" bit enabled. Note that on XR16C850s, we need to - * reset LCR to write to IER. - */ -static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) -{ - /* - * Exar UARTs have a SLEEP register that enables or disables - * each UART to enter sleep mode separately. On the XR17V35x the - * register is accessible to each UART at the UART_EXAR_SLEEP - * offset but the UART channel may only write to the corresponding - * bit. - */ - if ((p->port.type == PORT_XR17V35X) || - (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, 0xff); - return; - } - - if (p->capabilities & UART_CAP_SLEEP) { - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, 0); - serial_out(p, UART_LCR, 0); - } - } -} - -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; -} - -static void enable_rsa(struct uart_8250_port *up) -{ - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_out(up, UART_RSA_FRR, 0); - } -} - -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } -} -#endif /* CONFIG_SERIAL_8250_RSA */ - -/* - * This is a quickie test to see how big the FIFO is. - * It doesn't work at all the time, more's the pity. - */ -static int size_fifo(struct uart_8250_port *up) -{ - unsigned char old_fcr, old_mcr, old_lcr; - unsigned short old_dl; - int count; - - old_lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, 0); - old_fcr = serial_in(up, UART_FCR); - old_mcr = serial_in(up, UART_MCR); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_MCR, UART_MCR_LOOP); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - old_dl = serial_dl_read(up); - serial_dl_write(up, 0x0001); - serial_out(up, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_out(up, UART_TX, count); - mdelay(20);/* FIXME - schedule_timeout */ - for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_in(up, UART_RX); - serial_out(up, UART_FCR, old_fcr); - serial_out(up, UART_MCR, old_mcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_dl_write(up, old_dl); - serial_out(up, UART_LCR, old_lcr); - - return count; -} - -/* - * Read UART ID using the divisor method - set DLL and DLM to zero - * and the revision will be in DLL and device type in DLM. We - * preserve the device state across this. - */ -static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) -{ - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; - - old_lcr = serial_in(p, UART_LCR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); - - old_dll = serial_in(p, UART_DLL); - old_dlm = serial_in(p, UART_DLM); - - serial_out(p, UART_DLL, 0); - serial_out(p, UART_DLM, 0); - - id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - - serial_out(p, UART_DLL, old_dll); - serial_out(p, UART_DLM, old_dlm); - serial_out(p, UART_LCR, old_lcr); - - return id; -} - -/* - * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. - * When this function is called we know it is at least a StarTech - * 16650 V2, but it might be one of several StarTech UARTs, or one of - * its clones. (We treat the broken original StarTech 16650 V1 as a - * 16550, and why not? Startech doesn't seem to even acknowledge its - * existence.) - * - * What evil have men's minds wrought... - */ -static void autoconfig_has_efr(struct uart_8250_port *up) -{ - unsigned int id1, id2, id3, rev; - - /* - * Everything with an EFR has SLEEP - */ - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - - /* - * First we check to see if it's an Oxford Semiconductor UART. - * - * If we have to do this here because some non-National - * Semiconductor clone chips lock up if you try writing to the - * LSR register (which serial_icr_read does) - */ - - /* - * Check for Oxford Semiconductor 16C950. - * - * EFR [4] must be set else this test fails. - * - * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) - * claims that it's needed for 952 dual UART's (which are not - * recommended for new designs). - */ - up->acr = 0; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0x00); - id1 = serial_icr_read(up, UART_ID1); - id2 = serial_icr_read(up, UART_ID2); - id3 = serial_icr_read(up, UART_ID3); - rev = serial_icr_read(up, UART_REV); - - DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); - - if (id1 == 0x16 && id2 == 0xC9 && - (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { - up->port.type = PORT_16C950; - - /* - * Enable work around for the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if (id3 == 0x52 && rev == 0x01) - up->bugs |= UART_BUG_QUOT; - return; - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and then - * reading back DLL and DLM. The chip type depends on the DLM - * value read back: - * 0x10 - XR16C850 and the DLL contains the chip revision. - * 0x12 - XR16C2850. - * 0x14 - XR16C854. - */ - id1 = autoconfig_read_divisor_id(up); - DEBUG_AUTOCONF("850id=%04x ", id1); - - id2 = id1 >> 8; - if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { - up->port.type = PORT_16850; - return; - } - - /* - * It wasn't an XR16C850. - * - * We distinguish between the '654 and the '650 by counting - * how many bytes are in the FIFO. I'm using this for now, - * since that's the technique that was sent to me in the - * serial driver update, but I'm not convinced this works. - * I've had problems doing this in the past. -TYT - */ - if (size_fifo(up) == 64) - up->port.type = PORT_16654; - else - up->port.type = PORT_16650V2; -} - -/* - * We detected a chip without a FIFO. Only two fall into - * this category - the original 8250 and the 16450. The - * 16450 has a scratch register (accessible with LCR=0) - */ -static void autoconfig_8250(struct uart_8250_port *up) -{ - unsigned char scratch, status1, status2; - - up->port.type = PORT_8250; - - scratch = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, scratch); - - if (status1 == 0xa5 && status2 == 0x5a) - up->port.type = PORT_16450; -} - -static int broken_efr(struct uart_8250_port *up) -{ - /* - * Exar ST16C2550 "A2" devices incorrectly detect as - * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html - */ - if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) - return 1; - - return 0; -} - -static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) -{ - unsigned char status; - - status = serial_in(up, 0x04); /* EXCR2 */ -#define PRESL(x) ((x) & 0x30) - if (PRESL(status) == 0x10) { - /* already in high speed mode */ - return 0; - } else { - status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ - status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_out(up, 0x04, status); - } - return 1; -} - -/* - * We know that the chip has FIFOs. Does it have an EFR? The - * EFR is located in the same register position as the IIR and - * we know the top two bits of the IIR are currently set. The - * EFR should contain zero. Try to read the EFR. - */ -static void autoconfig_16550a(struct uart_8250_port *up) -{ - unsigned char status1, status2; - unsigned int iersave; - - up->port.type = PORT_16550A; - up->capabilities |= UART_CAP_FIFO; - - /* - * XR17V35x UARTs have an extra divisor register, DLD - * that gets enabled with when DLAB is set which will - * cause the device to incorrectly match and assign - * port type to PORT_16650. The EFR for this UART is - * found at offset 0x09. Instead check the Deice ID (DVID) - * register for a 2, 4 or 8 port UART. - */ - if (up->port.flags & UPF_EXAR_EFR) { - status1 = serial_in(up, UART_EXAR_DVID); - if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { - DEBUG_AUTOCONF("Exar XR17V35x "); - up->port.type = PORT_XR17V35X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - } - - /* - * Check for presence of the EFR when DLAB is set. - * Only ST16C650V1 UARTs pass this test. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - if (serial_in(up, UART_EFR) == 0) { - serial_out(up, UART_EFR, 0xA8); - if (serial_in(up, UART_EFR) != 0) { - DEBUG_AUTOCONF("EFRv1 "); - up->port.type = PORT_16650; - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - } else { - DEBUG_AUTOCONF("Motorola 8xxx DUART "); - } - serial_out(up, UART_EFR, 0); - return; - } - - /* - * Maybe it requires 0xbf to be written to the LCR. - * (other ST16C650V2 UARTs, TI16C752A, etc) - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { - DEBUG_AUTOCONF("EFRv2 "); - autoconfig_has_efr(up); - return; - } - - /* - * Check for a National Semiconductor SuperIO chip. - * Attempt to switch to bank 2, read the value of the LOOP bit - * from EXCR1. Switch back to bank 0, change it in MCR. Then - * switch back to bank 2, read it from EXCR1 again and check - * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - */ - serial_out(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - - if (!((status2 ^ status1) & UART_MCR_LOOP)) { - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1); - - if ((status2 ^ status1) & UART_MCR_LOOP) { - unsigned short quot; - - serial_out(up, UART_LCR, 0xE0); - - quot = serial_dl_read(up); - quot <<= 3; - - if (ns16550a_goto_highspeed(up)) - serial_dl_write(up, quot); - - serial_out(up, UART_LCR, 0); - - up->port.uartclk = 921600*16; - up->port.type = PORT_NS16550A; - up->capabilities |= UART_NATSEMI; - return; - } - } - - /* - * No EFR. Try to detect a TI16750, which only sets bit 5 of - * the IIR when 64 byte FIFO mode is enabled when DLAB is set. - * Try setting it with and without DLAB set. Cheap clones - * set bit 5 without DLAB set. - */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status2 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, 0); - - DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); - - if (status1 == 6 && status2 == 7) { - up->port.type = PORT_16750; - up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; - return; - } - - /* - * Try writing and reading the UART_IER_UUE bit (b6). - * If it works, this is probably one of the Xscale platform's - * internal UARTs. - * We're going to explicitly set the UUE bit to 0 before - * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. - */ - iersave = serial_in(up, UART_IER); - serial_out(up, UART_IER, iersave & ~UART_IER_UUE); - if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { - /* - * OK it's in a known zero state, try writing and reading - * without disturbing the current state of the other bits. - */ - serial_out(up, UART_IER, iersave | UART_IER_UUE); - if (serial_in(up, UART_IER) & UART_IER_UUE) { - /* - * It's an Xscale. - * We'll leave the UART_IER_UUE bit set to 1 (enabled). - */ - DEBUG_AUTOCONF("Xscale "); - up->port.type = PORT_XSCALE; - up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; - return; - } - } else { - /* - * If we got here we couldn't force the IER_UUE bit to 0. - * Log it and continue. - */ - DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); - } - serial_out(up, UART_IER, iersave); - - /* - * Exar uarts have EFR in a weird location - */ - if (up->port.flags & UPF_EXAR_EFR) { - DEBUG_AUTOCONF("Exar XR17D15x "); - up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - /* - * We distinguish between 16550A and U6 16550A by counting - * how many bytes are in the FIFO. - */ - if (up->port.type == PORT_16550A && size_fifo(up) == 64) { - up->port.type = PORT_U6_16550A; - up->capabilities |= UART_CAP_AFE; - } -} - -/* - * This routine is called by rs_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) -{ - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int old_capabilities; - - if (!port->iobase && !port->mapbase && !port->membase) - return; - - DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(port), port->iobase, port->membase); - - /* - * We really do need global IRQs disabled here - we're going to - * be frobbing the chips IRQ enable register to see if it exists. - */ - spin_lock_irqsave(&port->lock, flags); - - up->capabilities = 0; - up->bugs = 0; - - if (!(port->flags & UPF_BUGGY_UART)) { - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against - * false positives due to ISA bus float. The - * assumption is that 0x80 is a non-existent port; - * which should be safe since include/asm/io.h also - * makes this assumption. - * - * Note: this is safe as long as MCR bit 4 is clear - * and the device is in "PC" mode. - */ - scratch = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - /* - * Mask out IER[7:4] bits for test as some UARTs (e.g. TL - * 16C754B) allow only to modify them if an EFR bit is set. - */ - scratch2 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { - /* - * We failed; there's nothing here - */ - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; - } - } - - save_mcr = serial_in(up, UART_MCR); - save_lcr = serial_in(up, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(port->flags & UPF_SKIP_TEST)) { - serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_in(up, UART_MSR) & 0xF0; - serial_out(up, UART_MCR, save_mcr); - if (status1 != 0x90) { - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; - } - } - - /* - * We're pretty sure there's a port here. Lets find out what - * type of port it is. The IIR top two bits allows us to find - * out if it's 8250 or 16450, 16550, 16550A or later. This - * determines what we test for next. - * - * We also initialise the EFR (if any) to zero for later. The - * EFR occupies the same register location as the FCR and IIR. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, 0); - serial_out(up, UART_LCR, 0); - - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(up, UART_IIR) >> 6; - - switch (scratch) { - case 0: - autoconfig_8250(up); - break; - case 1: - port->type = PORT_UNKNOWN; - break; - case 2: - port->type = PORT_16550; - break; - case 3: - autoconfig_16550a(up); - break; - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Only probe for RSA ports if we got the region. - */ - if (port->type == PORT_16550A && probeflags & PROBE_RSA) { - int i; - - for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { - port->type = PORT_RSA; - break; - } - } - } -#endif - - serial_out(up, UART_LCR, save_lcr); - - port->fifosize = uart_config[up->port.type].fifo_size; - old_capabilities = up->capabilities; - up->capabilities = uart_config[port->type].flags; - up->tx_loadsz = uart_config[port->type].tx_loadsz; - - if (port->type == PORT_UNKNOWN) - goto out_lock; - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) - serial_out(up, UART_RSA_FRR, 0); -#endif - serial_out(up, UART_MCR, save_mcr); - serial8250_clear_fifos(up); - serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); - -out_lock: - spin_unlock_irqrestore(&port->lock, flags); - if (up->capabilities != old_capabilities) { - printk(KERN_WARNING - "ttyS%d: detected caps %08x should be %08x\n", - serial_index(port), old_capabilities, - up->capabilities); - } -out: - DEBUG_AUTOCONF("iir=%d ", scratch); - DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); -} - -static void autoconfig_irq(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned char save_mcr, save_ier; - unsigned char save_ICP = 0; - unsigned int ICP = 0; - unsigned long irqs; - int irq; - - if (port->flags & UPF_FOURPORT) { - ICP = (port->iobase & 0xfe0) | 0x1f; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - inb_p(ICP); - } - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_in(up, UART_MCR); - save_ier = serial_in(up, UART_IER); - serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_out(up, UART_MCR, 0); - udelay(10); - if (port->flags & UPF_FOURPORT) { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_out(up, UART_IER, 0x0f); /* enable all intrs */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); - serial_out(up, UART_TX, 0xFF); - udelay(20); - irq = probe_irq_off(irqs); - - serial_out(up, UART_MCR, save_mcr); - serial_out(up, UART_IER, save_ier); - - if (port->flags & UPF_FOURPORT) - outb_p(save_ICP, ICP); - - port->irq = (irq > 0) ? irq : 0; -} - -static inline void __stop_tx(struct uart_8250_port *p) -{ - if (p->ier & UART_IER_THRI) { - p->ier &= ~UART_IER_THRI; - serial_out(p, UART_IER, p->ier); - } -} - -static void serial8250_stop_tx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - __stop_tx(up); - - /* - * We really want to stop the transmitter from sending. - */ - if (port->type == PORT_16C950) { - up->acr |= UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void serial8250_start_tx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - if (up->dma && !serial8250_tx_dma(up)) { - return; - } else if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_port_out(port, UART_IER, up->ier); - - if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if (lsr & UART_LSR_TEMT) - serial8250_tx_chars(up); - } - } - - /* - * Re-enable the transmitter if we disabled it. - */ - if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { - up->acr &= ~UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void serial8250_stop_rx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_port_out(port, UART_IER, up->ier); -} - -static void serial8250_enable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier |= UART_IER_MSI; - serial_port_out(port, UART_IER, up->ier); -} - -/* - * serial8250_rx_chars: processes according to the passed in LSR - * value, and returns the remaining LSR bits not handled - * by this Rx routine. - */ -unsigned char -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) -{ - struct uart_port *port = &up->port; - unsigned char ch; - int max_count = 256; - char flag; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - else - /* - * Intel 82571 has a Serial Over Lan device that will - * set UART_LSR_BI without setting UART_LSR_DR when - * it receives a break. To avoid reading from the - * receive buffer without UART_LSR_DR bit set, we - * just force the read character to be 0 - */ - ch = 0; - - flag = TTY_NORMAL; - port->icount.rx++; - - lsr |= up->lsr_saved_flags; - up->lsr_saved_flags = 0; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) - port->icount.parity++; - else if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= port->read_status_mask; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); - return lsr; -} -EXPORT_SYMBOL_GPL(serial8250_rx_chars); - -void serial8250_tx_chars(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - serial_out(up, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - if (uart_tx_stopped(port)) { - serial8250_stop_tx(port); - return; - } - if (uart_circ_empty(xmit)) { - __stop_tx(up); - return; - } - - count = up->tx_loadsz; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - if (up->capabilities & UART_CAP_HFIFO) { - if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != - BOTH_EMPTY) - break; - } - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - DEBUG_INTR("THRE..."); - - if (uart_circ_empty(xmit)) - __stop_tx(up); -} -EXPORT_SYMBOL_GPL(serial8250_tx_chars); - -unsigned int serial8250_modem_status(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned int status = serial_in(up, UART_MSR); - - status |= up->msr_saved_flags; - up->msr_saved_flags = 0; - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - port->state != NULL) { - if (status & UART_MSR_TERI) - port->icount.rng++; - if (status & UART_MSR_DDSR) - port->icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(port, status & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - } - - return status; -} -EXPORT_SYMBOL_GPL(serial8250_modem_status); - -/* - * This handles the interrupt from one port. - */ -int serial8250_handle_irq(struct uart_port *port, unsigned int iir) -{ - unsigned char status; - unsigned long flags; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int dma_err = 0; - - if (iir & UART_IIR_NO_INT) - return 0; - - spin_lock_irqsave(&port->lock, flags); - - status = serial_port_in(port, UART_LSR); - - DEBUG_INTR("status = %x...", status); - - if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (up->dma) - dma_err = serial8250_rx_dma(up, iir); - - if (!up->dma || dma_err) - status = serial8250_rx_chars(up, status); - } - serial8250_modem_status(up); - if (status & UART_LSR_THRE) - serial8250_tx_chars(up); - - spin_unlock_irqrestore(&port->lock, flags); - return 1; -} -EXPORT_SYMBOL_GPL(serial8250_handle_irq); - -static int serial8250_default_handle_irq(struct uart_port *port) -{ - unsigned int iir = serial_port_in(port, UART_IIR); - - return serial8250_handle_irq(port, iir); -} - -/* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned char int0, int1, int2, int3; - unsigned int iir = serial_port_in(port, UART_IIR); - int ret; - - ret = serial8250_handle_irq(port, iir); - - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) { - int0 = serial_port_in(port, 0x80); - int1 = serial_port_in(port, 0x81); - int2 = serial_port_in(port, 0x82); - int3 = serial_port_in(port, 0x83); - } - - return ret; -} - -/* - * This is the serial driver's interrupt routine. - * - * Arjan thinks the old way was overly complex, so it got simplified. - * Alan disagrees, saying that need the complexity to handle the weird - * nature of ISA shared interrupts. (This is a special exception.) - * - * In order to handle ISA shared interrupts properly, we need to check - * that all ports have been serviced, and therefore the ISA interrupt - * line has been de-asserted. - * - * This means we need to loop through all ports. checking that they - * don't have an interrupt pending. - */ -static irqreturn_t serial8250_interrupt(int irq, void *dev_id) -{ - struct irq_info *i = dev_id; - struct list_head *l, *end = NULL; - int pass_counter = 0, handled = 0; - - DEBUG_INTR("serial8250_interrupt(%d)...", irq); - - spin_lock(&i->lock); - - l = i->head; - do { - struct uart_8250_port *up; - struct uart_port *port; - - up = list_entry(l, struct uart_8250_port, list); - port = &up->port; - - if (port->handle_irq(port)) { - handled = 1; - end = NULL; - } else if (end == NULL) - end = l; - - l = l->next; - - if (l == i->head && pass_counter++ > PASS_LIMIT) { - /* If we hit this, we're dead. */ - printk_ratelimited(KERN_ERR - "serial8250: too much work for irq%d\n", irq); - break; - } - } while (l != end); - - spin_unlock(&i->lock); - - DEBUG_INTR("end.\n"); - - return IRQ_RETVAL(handled); -} - -/* - * To support ISA shared interrupts, we need to have one interrupt - * handler that ensures that the IRQ line has been deasserted - * before returning. Failing to do this will result in the IRQ - * line being stuck active, and, since ISA irqs are edge triggered, - * no more IRQs will be seen. - */ -static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) -{ - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &up->list) - i->head = i->head->next; - list_del(&up->list); - } else { - BUG_ON(i->head != &up->list); - i->head = NULL; - } - spin_unlock_irq(&i->lock); - /* List empty so throw away the hash node */ - if (i->head == NULL) { - hlist_del(&i->node); - kfree(i); - } -} - -static int serial_link_irq_chain(struct uart_8250_port *up) -{ - struct hlist_head *h; - struct hlist_node *n; - struct irq_info *i; - int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - if (n == NULL) { - i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); - if (i == NULL) { - mutex_unlock(&hash_mutex); - return -ENOMEM; - } - spin_lock_init(&i->lock); - i->irq = up->port.irq; - hlist_add_head(&i->node, h); - } - mutex_unlock(&hash_mutex); - - spin_lock_irq(&i->lock); - - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); - - ret = 0; - } else { - INIT_LIST_HEAD(&up->list); - i->head = &up->list; - spin_unlock_irq(&i->lock); - irq_flags |= up->port.irqflags; - ret = request_irq(up->port.irq, serial8250_interrupt, - irq_flags, "serial", i); - if (ret < 0) - serial_do_unlink(i, up); - } - - return ret; -} - -static void serial_unlink_irq_chain(struct uart_8250_port *up) -{ - struct irq_info *i; - struct hlist_node *n; - struct hlist_head *h; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - BUG_ON(n == NULL); - BUG_ON(i->head == NULL); - - if (list_empty(i->head)) - free_irq(up->port.irq, i); - - serial_do_unlink(i, up); - mutex_unlock(&hash_mutex); -} - -/* - * This function is used to handle ports that do not have an - * interrupt. This doesn't work very well for 16450's, but gives - * barely passable results for a 16550A. (Although at the expense - * of much CPU overhead). - */ -static void serial8250_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - - up->port.handle_irq(&up->port); - mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); -} - -static void serial8250_backup_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int iir, ier = 0, lsr; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Must disable interrupts or else we risk racing with the interrupt - * based handler. - */ - if (up->port.irq) { - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - } - - iir = serial_in(up, UART_IIR); - - /* - * This should be a safe test for anyone who doesn't trust the - * IIR bits on their UART, but it's specifically designed for - * the "Diva" UART used on the management processor on many HP - * ia64 and parisc boxes. - */ - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && - (lsr & UART_LSR_THRE)) { - iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); - iir |= UART_IIR_THRI; - } - - if (!(iir & UART_IIR_NO_INT)) - serial8250_tx_chars(up); - - if (up->port.irq) - serial_out(up, UART_IER, ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, - jiffies + uart_poll_timeout(&up->port) + HZ / 5); -} - -static unsigned int serial8250_tx_empty(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - unsigned int lsr; - - spin_lock_irqsave(&port->lock, flags); - lsr = serial_port_in(port, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&port->lock, flags); - - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int serial8250_get_mctrl(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned int status; - unsigned int ret; - - status = serial8250_modem_status(up); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - - serial_port_out(port, UART_MCR, mcr); -} - -static void serial8250_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_port_out(port, UART_LCR, up->lcr); - spin_unlock_irqrestore(&port->lock, flags); -} - -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - for (;;) { - status = serial_in(up, UART_LSR); - - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; - - if ((status & bits) == bits) - break; - if (--tmout == 0) - break; - udelay(1); - } - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { - unsigned int msr = serial_in(up, UART_MSR); - up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) - break; - udelay(1); - touch_nmi_watchdog(); - } - } -} - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int serial8250_get_poll_char(struct uart_port *port) -{ - unsigned char lsr = serial_port_in(port, UART_LSR); - - if (!(lsr & UART_LSR_DR)) - return NO_POLL_CHAR; - - return serial_port_in(port, UART_RX); -} - - -static void serial8250_put_poll_char(struct uart_port *port, - unsigned char c) -{ - unsigned int ier; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - wait_for_xmitr(up, BOTH_EMPTY); - /* - * Send the character out. - * If a LF, also do CR... - */ - serial_port_out(port, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_TX, 13); - } - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -static int serial8250_startup(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - unsigned char lsr, iir; - int retval; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - if (!port->fifosize) - port->fifosize = uart_config[port->type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[port->type].flags; - up->mcr = 0; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - if (port->type == PORT_16C950) { - /* Wake up and initialize UART */ - up->acr = 0; - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_IER, 0); - serial_port_out(port, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial8250_clear_fifos(up); - - /* - * Clear the interrupt registers. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(port->flags & UPF_BUGGY_UART) && - (serial_port_in(port, UART_LSR) == 0xff)) { - printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(port)); - return -ENODEV; - } - - /* - * For a XR16C850, we need to set the trigger levels - */ - if (port->type == PORT_16850) { - unsigned char fctr; - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_port_out(port, UART_TRG, UART_TRG_96); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_port_out(port, UART_TRG, UART_TRG_96); - - serial_port_out(port, UART_LCR, 0); - } - - if (port->irq) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&port->lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(port->irq); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir1 = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - - if (port->irqflags & IRQF_SHARED) - enable_irq(port->irq); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * If the interrupt is not reasserted, or we otherwise - * don't trust the iir, setup a timer to kick the UART - * on a regular basis. - */ - if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || - up->port.flags & UPF_BUG_THRE) { - up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); - } - } - - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!port->irq) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else { - retval = serial_link_irq_chain(up); - if (retval) - return retval; - } - - /* - * Now, initialize the UART - */ - serial_port_out(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&port->lock, flags); - if (up->port.flags & UPF_FOURPORT) { - if (!up->port.irq) - up->port.mctrl |= TIOCM_OUT1; - } else - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ - if (port->irq) - up->port.mctrl |= TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. - */ - if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) - goto dont_test_tx_en; - - /* - * Do a quick test to see if we receive an - * interrupt when we enable the TX irq. - */ - serial_port_out(port, UART_IER, UART_IER_THRI); - lsr = serial_port_in(port, UART_LSR); - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { - up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); - } - } else { - up->bugs &= ~UART_BUG_TXEN; - } - -dont_test_tx_en: - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Clear the interrupt registers again for luck, and clear the - * saved flags to avoid getting false values from polling - * routines or the previous session. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - up->lsr_saved_flags = 0; - up->msr_saved_flags = 0; - - /* - * Request DMA channels for both RX and TX. - */ - if (up->dma) { - retval = serial8250_request_dma(up); - if (retval) { - pr_warn_ratelimited("ttyS%d - failed to request DMA\n", - serial_index(port)); - up->dma = NULL; - } - } - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_port_out(port, UART_IER, up->ier); - - if (port->flags & UPF_FOURPORT) { - unsigned int icp; - /* - * Enable interrupts on the AST Fourport board - */ - icp = (port->iobase & 0xfe0) | 0x01f; - outb_p(0x80, icp); - inb_p(icp); - } - - return 0; -} - -static void serial8250_shutdown(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_port_out(port, UART_IER, 0); - - if (up->dma) - serial8250_release_dma(up); - - spin_lock_irqsave(&port->lock, flags); - if (port->flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((port->iobase & 0xfe0) | 0x1f); - port->mctrl |= TIOCM_OUT1; - } else - port->mctrl &= ~TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_port_out(port, UART_LCR, - serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); - serial8250_clear_fifos(up); - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif - - /* - * Read data port to reset things, and then unlink from - * the IRQ chain. - */ - serial_port_in(port, UART_RX); - - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (port->irq) - serial_unlink_irq_chain(up); -} - -static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) -{ - unsigned int quot; - - /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. - */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) - quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) - quot = 0x8002; - else - quot = uart_get_divisor(port, baud); - - return quot; -} - -void -serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - int fifo_bug = 0; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) { - cval |= UART_LCR_PARITY; - if (up->bugs & UART_BUG_PARITY) - fifo_bug = 1; - } - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(port, baud); - - /* - * Oxford Semi 952 rev B workaround - */ - if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) - quot++; - - if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - fcr = uart_config[port->type].fcr; - if (baud < 2400 || fifo_bug) { - fcr &= ~UART_FCR_TRIGGER_MASK; - fcr |= UART_FCR_TRIGGER_1; - } - } - - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. - */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - } - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - if (up->capabilities & UART_CAP_UUE) - up->ier |= UART_IER_UUE; - if (up->capabilities & UART_CAP_RTOIE) - up->ier |= UART_IER_RTOIE; - - serial_port_out(port, UART_IER, up->ier); - - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; - /* - * TI16C752/Startech hardware flow control. FIXME: - * - TI16C752 requires control thresholds to be set. - * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. - */ - if (termios->c_cflag & CRTSCTS) - efr |= UART_EFR_CTS; - - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - if (port->flags & UPF_EXAR_EFR) - serial_port_out(port, UART_XR_EFR, efr); - else - serial_port_out(port, UART_EFR, efr); - } - - /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (is_omap1510_8250(up)) { - if (baud == 115200) { - quot = 1; - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); - } else - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); - } - - /* - * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, - * otherwise just set DLAB - */ - if (up->capabilities & UART_NATSEMI) - serial_port_out(port, UART_LCR, 0xe0); - else - serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB); - - serial_dl_write(up, quot); - - /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR - * is written without DLAB set, this mode will be disabled. - */ - if (port->type == PORT_16750) - serial_port_out(port, UART_FCR, fcr); - - serial_port_out(port, UART_LCR, cval); /* reset DLAB */ - up->lcr = cval; /* Save LCR */ - if (port->type != PORT_16750) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - if (fcr & UART_FCR_ENABLE_FIFO) - serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_port_out(port, UART_FCR, fcr); /* set fcr */ - } - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); -} -EXPORT_SYMBOL(serial8250_do_set_termios); - -static void -serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - if (port->set_termios) - port->set_termios(port, termios, old); - else - serial8250_do_set_termios(port, termios, old); -} - -static void -serial8250_set_ldisc(struct uart_port *port, int new) -{ - if (new == N_PPS) { - port->flags |= UPF_HARDPPS_CD; - serial8250_enable_ms(port); - } else - port->flags &= ~UPF_HARDPPS_CD; -} - - -void serial8250_do_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_8250_port *p = - container_of(port, struct uart_8250_port, port); - - serial8250_set_sleep(p, state != 0); -} -EXPORT_SYMBOL(serial8250_do_pm); - -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - if (port->pm) - port->pm(port, state, oldstate); - else - serial8250_do_pm(port, state, oldstate); -} - -static unsigned int serial8250_port_size(struct uart_8250_port *pt) -{ - if (pt->port.iotype == UPIO_AU) - return 0x1000; - if (is_omap1_8250(pt)) - return 0x16 << pt->port.regshift; - - return 8 << pt->port.regshift; -} - -/* - * Resource handling. - */ -static int serial8250_request_std_resource(struct uart_8250_port *up) -{ - unsigned int size = serial8250_port_size(up); - struct uart_port *port = &up->port; - int ret = 0; - - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM: - if (!port->mapbase) - break; - - if (!request_mem_region(port->mapbase, size, "serial")) { - ret = -EBUSY; - break; - } - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); - if (!port->membase) { - release_mem_region(port->mapbase, size); - ret = -ENOMEM; - } - } - break; - - case UPIO_HUB6: - case UPIO_PORT: - if (!request_region(port->iobase, size, "serial")) - ret = -EBUSY; - break; - } - return ret; -} - -static void serial8250_release_std_resource(struct uart_8250_port *up) -{ - unsigned int size = serial8250_port_size(up); - struct uart_port *port = &up->port; - - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM: - if (!port->mapbase) - break; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - release_mem_region(port->mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase, size); - break; - } -} - -static int serial8250_request_rsa_resource(struct uart_8250_port *up) -{ - unsigned long start = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; - struct uart_port *port = &up->port; - int ret = -EINVAL; - - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - start += port->iobase; - if (request_region(start, size, "serial-rsa")) - ret = 0; - else - ret = -EBUSY; - break; - } - - return ret; -} - -static void serial8250_release_rsa_resource(struct uart_8250_port *up) -{ - unsigned long offset = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; - struct uart_port *port = &up->port; - - switch (port->iotype) { - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase + offset, size); - break; - } -} - -static void serial8250_release_port(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - serial8250_release_std_resource(up); - if (port->type == PORT_RSA) - serial8250_release_rsa_resource(up); -} - -static int serial8250_request_port(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int ret; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - ret = serial8250_request_std_resource(up); - if (ret == 0 && port->type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - serial8250_release_std_resource(up); - } - - return ret; -} - -static void serial8250_config_port(struct uart_port *port, int flags) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int probeflags = PROBE_ANY; - int ret; - - if (port->type == PORT_8250_CIR) - return; - - /* - * Find the region that we can probe for. This in turn - * tells us whether we can probe for the type of port. - */ - ret = serial8250_request_std_resource(up); - if (ret < 0) - return; - - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - probeflags &= ~PROBE_RSA; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - if (flags & UART_CONFIG_TYPE) - autoconfig(up, probeflags); - - /* if access method is AU, it is a 16550 with a quirk */ - if (port->type == PORT_16550A && port->iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; - - if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) - autoconfig_irq(up); - - if (port->type != PORT_RSA && probeflags & PROBE_RSA) - serial8250_release_rsa_resource(up); - if (port->type == PORT_UNKNOWN) - serial8250_release_std_resource(up); - - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; -} - -static int -serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if (ser->irq >= nr_irqs || ser->irq < 0 || - ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || - ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || - ser->type == PORT_STARTECH) - return -EINVAL; - return 0; -} - -static const char * -serial8250_type(struct uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - -static struct uart_ops serial8250_pops = { - .tx_empty = serial8250_tx_empty, - .set_mctrl = serial8250_set_mctrl, - .get_mctrl = serial8250_get_mctrl, - .stop_tx = serial8250_stop_tx, - .start_tx = serial8250_start_tx, - .stop_rx = serial8250_stop_rx, - .enable_ms = serial8250_enable_ms, - .break_ctl = serial8250_break_ctl, - .startup = serial8250_startup, - .shutdown = serial8250_shutdown, - .set_termios = serial8250_set_termios, - .set_ldisc = serial8250_set_ldisc, - .pm = serial8250_pm, - .type = serial8250_type, - .release_port = serial8250_release_port, - .request_port = serial8250_request_port, - .config_port = serial8250_config_port, - .verify_port = serial8250_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = serial8250_get_poll_char, - .poll_put_char = serial8250_put_poll_char, -#endif -}; - -static struct uart_8250_port serial8250_ports[UART_NR]; - -static void (*serial8250_isa_config)(int port, struct uart_port *up, - unsigned short *capabilities); - -void serial8250_set_isa_configurator( - void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) -{ - serial8250_isa_config = v; -} -EXPORT_SYMBOL(serial8250_set_isa_configurator); - -static void __init serial8250_isa_init_ports(void) -{ - struct uart_8250_port *up; - static int first = 1; - int i, irqflag = 0; - - if (!first) - return; - first = 0; - - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - struct uart_port *port = &up->port; - - port->line = i; - spin_lock_init(&port->lock); - - init_timer(&up->timer); - up->timer.function = serial8250_timeout; - up->cur_iotype = 0xFF; - - /* - * ALPHA_KLUDGE_MCR needs to be killed. - */ - up->mcr_mask = ~ALPHA_KLUDGE_MCR; - up->mcr_force = ALPHA_KLUDGE_MCR; - - port->ops = &serial8250_pops; - } - - if (share_irqs) - irqflag = IRQF_SHARED; - - for (i = 0, up = serial8250_ports; - i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; - i++, up++) { - struct uart_port *port = &up->port; - - port->iobase = old_serial_port[i].port; - port->irq = irq_canonicalize(old_serial_port[i].irq); - port->irqflags = old_serial_port[i].irqflags; - port->uartclk = old_serial_port[i].baud_base * 16; - port->flags = old_serial_port[i].flags; - port->hub6 = old_serial_port[i].hub6; - port->membase = old_serial_port[i].iomem_base; - port->iotype = old_serial_port[i].io_type; - port->regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(port); - port->irqflags |= irqflag; - if (serial8250_isa_config != NULL) - serial8250_isa_config(i, &up->port, &up->capabilities); - - } -} - -static void -serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) -{ - up->port.type = type; - if (!up->port.fifosize) - up->port.fifosize = uart_config[type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[type].flags; -} - -static void __init -serial8250_register_ports(struct uart_driver *drv, struct device *dev) -{ - int i; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.dev) - continue; - - up->port.dev = dev; - - if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(up, up->port.type); - - uart_add_one_port(drv, &up->port); - } -} - -#ifdef CONFIG_SERIAL_8250_CONSOLE - -static void serial8250_console_putchar(struct uart_port *port, int ch) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out(port, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial8250_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_8250_port *up = &serial8250_ports[co->index]; - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - local_irq_save(flags); - if (port->sysrq) { - /* serial8250_handle_irq() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - uart_console_write(port, s, count, serial8250_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); - - /* - * The receive handling will happen properly because the - * receive ready bit will still be set; it is not cleared - * on read. However, modem control will not, we must - * call it if we have saved something in the saved flags - * while processing with interrupts off. - */ - if (up->msr_saved_flags) - serial8250_modem_status(up); - - if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); -} - -static int __init serial8250_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= nr_uarts) - co->index = 0; - port = &serial8250_ports[co->index].port; - if (!port->iobase && !port->membase) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static int serial8250_console_early_setup(void) -{ - return serial8250_find_port_for_earlycon(); -} - -static struct console serial8250_console = { - .name = "ttyS", - .write = serial8250_console_write, - .device = uart_console_device, - .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, - .flags = CON_PRINTBUFFER | CON_ANYTIME, - .index = -1, - .data = &serial8250_reg, -}; - -static int __init serial8250_console_init(void) -{ - serial8250_isa_init_ports(); - register_console(&serial8250_console); - return 0; -} -console_initcall(serial8250_console_init); - -int serial8250_find_port(struct uart_port *p) -{ - int line; - struct uart_port *port; - - for (line = 0; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; - if (uart_match_port(p, port)) - return line; - } - return -ENODEV; -} - -#define SERIAL8250_CONSOLE &serial8250_console -#else -#define SERIAL8250_CONSOLE NULL -#endif - -static struct uart_driver serial8250_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .cons = SERIAL8250_CONSOLE, -}; - -/* - * early_serial_setup - early registration for 8250 ports - * - * Setup an 8250 port structure prior to console initialisation. Use - * after console initialisation will cause undefined behaviour. - */ -int __init early_serial_setup(struct uart_port *port) -{ - struct uart_port *p; - - if (port->line >= ARRAY_SIZE(serial8250_ports)) - return -ENODEV; - - serial8250_isa_init_ports(); - p = &serial8250_ports[port->line].port; - p->iobase = port->iobase; - p->membase = port->membase; - p->irq = port->irq; - p->irqflags = port->irqflags; - p->uartclk = port->uartclk; - p->fifosize = port->fifosize; - p->regshift = port->regshift; - p->iotype = port->iotype; - p->flags = port->flags; - p->mapbase = port->mapbase; - p->private_data = port->private_data; - p->type = port->type; - p->line = port->line; - - set_io_from_upio(p); - if (port->serial_in) - p->serial_in = port->serial_in; - if (port->serial_out) - p->serial_out = port->serial_out; - if (port->handle_irq) - p->handle_irq = port->handle_irq; - else - p->handle_irq = serial8250_default_handle_irq; - - return 0; -} - -/** - * serial8250_suspend_port - suspend one serial port - * @line: serial line number - * - * Suspend one serial port. - */ -void serial8250_suspend_port(int line) -{ - uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port); -} - -/** - * serial8250_resume_port - resume one serial port - * @line: serial line number - * - * Resume one serial port. - */ -void serial8250_resume_port(int line) -{ - struct uart_8250_port *up = &serial8250_ports[line]; - struct uart_port *port = &up->port; - - if (up->capabilities & UART_NATSEMI) { - /* Ensure it's still in high speed mode */ - serial_port_out(port, UART_LCR, 0xE0); - - ns16550a_goto_highspeed(up); - - serial_port_out(port, UART_LCR, 0); - port->uartclk = 921600*16; - } - uart_resume_port(&serial8250_reg, port); -} - -/* - * Register a set of serial devices attached to a platform device. The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. - */ -static int serial8250_probe(struct platform_device *dev) -{ - struct plat_serial8250_port *p = dev->dev.platform_data; - struct uart_8250_port uart; - int ret, i, irqflag = 0; - - memset(&uart, 0, sizeof(uart)); - - if (share_irqs) - irqflag = IRQF_SHARED; - - for (i = 0; p && p->flags != 0; p++, i++) { - uart.port.iobase = p->iobase; - uart.port.membase = p->membase; - uart.port.irq = p->irq; - uart.port.irqflags = p->irqflags; - uart.port.uartclk = p->uartclk; - uart.port.regshift = p->regshift; - uart.port.iotype = p->iotype; - uart.port.flags = p->flags; - uart.port.mapbase = p->mapbase; - uart.port.hub6 = p->hub6; - uart.port.private_data = p->private_data; - uart.port.type = p->type; - uart.port.serial_in = p->serial_in; - uart.port.serial_out = p->serial_out; - uart.port.handle_irq = p->handle_irq; - uart.port.handle_break = p->handle_break; - uart.port.set_termios = p->set_termios; - uart.port.pm = p->pm; - uart.port.dev = &dev->dev; - uart.port.irqflags |= irqflag; - ret = serial8250_register_8250_port(&uart); - if (ret < 0) { - dev_err(&dev->dev, "unable to register port at index %d " - "(IO%lx MEM%llx IRQ%d): %d\n", i, - p->iobase, (unsigned long long)p->mapbase, - p->irq, ret); - } - } - return 0; -} - -/* - * Remove serial ports registered against a platform device. - */ -static int serial8250_remove(struct platform_device *dev) -{ - int i; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.dev == &dev->dev) - serial8250_unregister_port(i); - } - return 0; -} - -static int serial8250_suspend(struct platform_device *dev, pm_message_t state) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial8250_reg, &up->port); - } - - return 0; -} - -static int serial8250_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - serial8250_resume_port(i); - } - - return 0; -} - -static struct platform_driver serial8250_isa_driver = { - .probe = serial8250_probe, - .remove = serial8250_remove, - .suspend = serial8250_suspend, - .resume = serial8250_resume, - .driver = { - .name = "serial8250", - .owner = THIS_MODULE, - }, -}; - -/* - * This "device" covers _all_ ISA 8250-compatible serial devices listed - * in the table in include/asm/serial.h - */ -static struct platform_device *serial8250_isa_devs; - -/* - * serial8250_register_8250_port and serial8250_unregister_port allows for - * 16x50 serial ports to be configured at run-time, to support PCMCIA - * modems and PCI multiport cards. - */ -static DEFINE_MUTEX(serial_mutex); - -static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) -{ - int i; - - /* - * First, find a port entry which matches. - */ - for (i = 0; i < nr_uarts; i++) - if (uart_match_port(&serial8250_ports[i].port, port)) - return &serial8250_ports[i]; - - /* - * We didn't find a matching entry, so look for the first - * free entry. We look for one which hasn't been previously - * used (indicated by zero iobase). - */ - for (i = 0; i < nr_uarts; i++) - if (serial8250_ports[i].port.type == PORT_UNKNOWN && - serial8250_ports[i].port.iobase == 0) - return &serial8250_ports[i]; - - /* - * That also failed. Last resort is to find any entry which - * doesn't have a real port associated with it. - */ - for (i = 0; i < nr_uarts; i++) - if (serial8250_ports[i].port.type == PORT_UNKNOWN) - return &serial8250_ports[i]; - - return NULL; -} - -/** - * serial8250_register_8250_port - register a serial port - * @up: serial port template - * - * Configure the serial port specified by the request. If the - * port exists and is in use, it is hung up and unregistered - * first. - * - * The port is then probed and if necessary the IRQ is autodetected - * If this fails an error is returned. - * - * On success the port is ready to use and the line number is returned. - */ -int serial8250_register_8250_port(struct uart_8250_port *up) -{ - struct uart_8250_port *uart; - int ret = -ENOSPC; - - if (up->port.uartclk == 0) - return -EINVAL; - - mutex_lock(&serial_mutex); - - uart = serial8250_find_match_or_unused(&up->port); - if (uart && uart->port.type != PORT_8250_CIR) { - if (uart->port.dev) - uart_remove_one_port(&serial8250_reg, &uart->port); - - uart->port.iobase = up->port.iobase; - uart->port.membase = up->port.membase; - uart->port.irq = up->port.irq; - uart->port.irqflags = up->port.irqflags; - uart->port.uartclk = up->port.uartclk; - uart->port.fifosize = up->port.fifosize; - uart->port.regshift = up->port.regshift; - uart->port.iotype = up->port.iotype; - uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; - uart->bugs = up->bugs; - uart->port.mapbase = up->port.mapbase; - uart->port.private_data = up->port.private_data; - uart->port.fifosize = up->port.fifosize; - uart->tx_loadsz = up->tx_loadsz; - uart->capabilities = up->capabilities; - - if (up->port.dev) - uart->port.dev = up->port.dev; - - if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(uart, up->port.type); - - set_io_from_upio(&uart->port); - /* Possibly override default I/O functions. */ - if (up->port.serial_in) - uart->port.serial_in = up->port.serial_in; - if (up->port.serial_out) - uart->port.serial_out = up->port.serial_out; - if (up->port.handle_irq) - uart->port.handle_irq = up->port.handle_irq; - /* Possibly override set_termios call */ - if (up->port.set_termios) - uart->port.set_termios = up->port.set_termios; - if (up->port.pm) - uart->port.pm = up->port.pm; - if (up->port.handle_break) - uart->port.handle_break = up->port.handle_break; - if (up->dl_read) - uart->dl_read = up->dl_read; - if (up->dl_write) - uart->dl_write = up->dl_write; - if (up->dma) - uart->dma = up->dma; - - if (serial8250_isa_config != NULL) - serial8250_isa_config(0, &uart->port, - &uart->capabilities); - - ret = uart_add_one_port(&serial8250_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; - } - mutex_unlock(&serial_mutex); - - return ret; -} -EXPORT_SYMBOL(serial8250_register_8250_port); - -/** - * serial8250_unregister_port - remove a 16x50 serial port at runtime - * @line: serial line number - * - * Remove one serial port. This may not be called from interrupt - * context. We hand the port back to the our control. - */ -void serial8250_unregister_port(int line) -{ - struct uart_8250_port *uart = &serial8250_ports[line]; - - mutex_lock(&serial_mutex); - uart_remove_one_port(&serial8250_reg, &uart->port); - if (serial8250_isa_devs) { - 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; - } - mutex_unlock(&serial_mutex); -} -EXPORT_SYMBOL(serial8250_unregister_port); - -static int __init serial8250_init(void) -{ - int ret; - - serial8250_isa_init_ports(); - - printk(KERN_INFO "Serial: 8250/16550 driver, " - "%d ports, IRQ sharing %sabled\n", nr_uarts, - share_irqs ? "en" : "dis"); - -#ifdef CONFIG_SPARC - ret = sunserial_register_minors(&serial8250_reg, UART_NR); -#else - serial8250_reg.nr = UART_NR; - ret = uart_register_driver(&serial8250_reg); -#endif - if (ret) - goto out; - - ret = serial8250_pnp_init(); - if (ret) - goto unreg_uart_drv; - - serial8250_isa_devs = platform_device_alloc("serial8250", - PLAT8250_DEV_LEGACY); - if (!serial8250_isa_devs) { - ret = -ENOMEM; - goto unreg_pnp; - } - - ret = platform_device_add(serial8250_isa_devs); - if (ret) - goto put_dev; - - serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); - - ret = platform_driver_register(&serial8250_isa_driver); - if (ret == 0) - goto out; - - platform_device_del(serial8250_isa_devs); -put_dev: - platform_device_put(serial8250_isa_devs); -unreg_pnp: - serial8250_pnp_exit(); -unreg_uart_drv: -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -out: - return ret; -} - -static void __exit serial8250_exit(void) -{ - struct platform_device *isa_dev = serial8250_isa_devs; - - /* - * This tells serial8250_unregister_port() not to re-register - * the ports (thereby making serial8250_isa_driver permanently - * in use.) - */ - serial8250_isa_devs = NULL; - - platform_driver_unregister(&serial8250_isa_driver); - platform_device_unregister(isa_dev); - - serial8250_pnp_exit(); - -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -} - -module_init(serial8250_init); -module_exit(serial8250_exit); - -EXPORT_SYMBOL(serial8250_suspend_port); -EXPORT_SYMBOL(serial8250_resume_port); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); - -module_param(share_irqs, uint, 0644); -MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" - " (unsafe)"); - -module_param(nr_uarts, uint, 0644); -MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); - -module_param(skip_txen_test, uint, 0644); -MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); - -#ifdef CONFIG_SERIAL_8250_RSA -module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); -MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); -#endif -MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); - -#ifndef MODULE -/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name - * working as well for the module options so we don't break people. We - * need to keep the names identical and the convenient macros will happily - * refuse to let us do that by failing the build with redefinition errors - * of global variables. So we stick them inside a dummy function to avoid - * those conflicts. The options still get parsed, and the redefined - * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive. - * - * This is hacky. I'm sorry. - */ -static void __used s8250_options(void) -{ -#undef MODULE_PARAM_PREFIX -#define MODULE_PARAM_PREFIX "8250." - - module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644); - module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644); - module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644); -#ifdef CONFIG_SERIAL_8250_RSA - __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, - ¶m_array_ops, .arr = &__param_arr_probe_rsa, - 0444, -1); -#endif -} -#else -MODULE_ALIAS("8250"); -#endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c new file mode 100644 index 000000000000..2d563cb9057e --- /dev/null +++ b/drivers/tty/serial/8250/8250_core.c @@ -0,0 +1,3448 @@ +/* + * Driver for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King. + * + * 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. + * + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. + * membase is an 'ioremapped' cookie. + */ + +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SPARC +#include +#endif + +#include +#include + +#include "8250.h" + +/* + * Configuration: + * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option + * is unsafe when used on edge-triggered interrupts. + */ +static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; + +static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; + +static struct uart_driver serial8250_reg; + +static int serial_index(struct uart_port *port) +{ + return (serial8250_reg.minor - 64) + port->line; +} + +static unsigned int skip_txen_test; /* force skip of txen test at init time */ + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif + +#define PASS_LIMIT 512 + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + + +#ifdef CONFIG_SERIAL_8250_DETECT_IRQ +#define CONFIG_SERIAL_DETECT_IRQ 1 +#endif +#ifdef CONFIG_SERIAL_8250_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS 1 +#endif + +/* + * HUB6 is always on. This will be removed once the header + * files have been cleaned. + */ +#define CONFIG_HUB6 1 + +#include +/* + * SERIAL_PORT_DFNS tells us about built-in ports that have no + * standard enumeration mechanism. Platforms that can find all + * serial ports via mechanisms like ACPI or PCI need not supply it. + */ +#ifndef SERIAL_PORT_DFNS +#define SERIAL_PORT_DFNS +#endif + +static const struct old_serial_port old_serial_port[] = { + SERIAL_PORT_DFNS /* defined in asm/serial.h */ +}; + +#define UART_NR CONFIG_SERIAL_8250_NR_UARTS + +#ifdef CONFIG_SERIAL_8250_RSA + +#define PORT_RSA_MAX 4 +static unsigned long probe_rsa[PORT_RSA_MAX]; +static unsigned int probe_rsa_count; +#endif /* CONFIG_SERIAL_8250_RSA */ + +struct irq_info { + struct hlist_node node; + int irq; + spinlock_t lock; /* Protects list not the hash */ + struct list_head *head; +}; + +#define NR_IRQ_HASH 32 /* Can be adjusted later */ +static struct hlist_head irq_lists[NR_IRQ_HASH]; +static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ + +/* + * Here we define the default xmit fifo size used for each type of UART. + */ +static const struct serial8250_config uart_config[] = { + [PORT_UNKNOWN] = { + .name = "unknown", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_8250] = { + .name = "8250", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16450] = { + .name = "16450", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550] = { + .name = "16550", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550A] = { + .name = "16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_CIRRUS] = { + .name = "Cirrus", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16650] = { + .name = "ST16650", + .fifo_size = 1, + .tx_loadsz = 1, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16650V2] = { + .name = "ST16650V2", + .fifo_size = 32, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16750] = { + .name = "TI16750", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, + }, + [PORT_STARTECH] = { + .name = "Startech", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16C950] = { + .name = "16C950/954", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + /* UART_CAP_EFR breaks billionon CF bluetooth card. */ + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, + }, + [PORT_16654] = { + .name = "ST16654", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16850] = { + .name = "XR16850", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_RSA] = { + .name = "RSA", + .fifo_size = 2048, + .tx_loadsz = 2048, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, + .flags = UART_CAP_FIFO, + }, + [PORT_NS16550A] = { + .name = "NS16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_NATSEMI, + }, + [PORT_XSCALE] = { + .name = "XScale", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, + }, + [PORT_OCTEON] = { + .name = "OCTEON", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_U6_16550A] = { + .name = "U6_16550A", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_TEGRA] = { + .name = "Tegra", + .fifo_size = 32, + .tx_loadsz = 8, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_01, + .flags = UART_CAP_FIFO | UART_CAP_RTOIE, + }, + [PORT_XR17D15X] = { + .name = "XR17D15X", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_XR17V35X] = { + .name = "XR17V35X", + .fifo_size = 256, + .tx_loadsz = 256, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | + UART_FCR_T_TRIG_11, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_LPC3220] = { + .name = "LPC3220", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | + UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO, + }, + [PORT_BRCM_TRUMANAGE] = { + .name = "TruManage", + .fifo_size = 1, + .tx_loadsz = 1024, + .flags = UART_CAP_HFIFO, + }, + [PORT_8250_CIR] = { + .name = "CIR port" + }, + [PORT_ALTR_16550_F32] = { + .name = "Altera 16550 FIFO32", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F64] = { + .name = "Altera 16550 FIFO64", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F128] = { + .name = "Altera 16550 FIFO128", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, +}; + +/* Uart divisor latch read */ +static int default_serial_dl_read(struct uart_8250_port *up) +{ + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static void default_serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); +} + +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) + +/* Au1x00/RT288x UART hardware has a weird register layout */ +static const u8 au_io_in_map[] = { + [UART_RX] = 0, + [UART_IER] = 2, + [UART_IIR] = 3, + [UART_LCR] = 5, + [UART_MCR] = 6, + [UART_LSR] = 7, + [UART_MSR] = 8, +}; + +static const u8 au_io_out_map[] = { + [UART_TX] = 1, + [UART_IER] = 2, + [UART_FCR] = 4, + [UART_LCR] = 5, + [UART_MCR] = 6, +}; + +static unsigned int au_serial_in(struct uart_port *p, int offset) +{ + offset = au_io_in_map[offset] << p->regshift; + return __raw_readl(p->membase + offset); +} + +static void au_serial_out(struct uart_port *p, int offset, int value) +{ + offset = au_io_out_map[offset] << p->regshift; + __raw_writel(value, p->membase + offset); +} + +/* Au1x00 haven't got a standard divisor latch */ +static int au_serial_dl_read(struct uart_8250_port *up) +{ + return __raw_readl(up->port.membase + 0x28); +} + +static void au_serial_dl_write(struct uart_8250_port *up, int value) +{ + __raw_writel(value, up->port.membase + 0x28); +} + +#endif + +static unsigned int hub6_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + return inb(p->iobase + 1); +} + +static void hub6_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + outb(value, p->iobase + 1); +} + +static unsigned int mem_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readb(p->membase + offset); +} + +static void mem_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writeb(value, p->membase + offset); +} + +static void mem32_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writel(value, p->membase + offset); +} + +static unsigned int mem32_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readl(p->membase + offset); +} + +static unsigned int io_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return inb(p->iobase + offset); +} + +static void io_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(value, p->iobase + offset); +} + +static int serial8250_default_handle_irq(struct uart_port *port); +static int exar_handle_irq(struct uart_port *port); + +static void set_io_from_upio(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + + up->dl_read = default_serial_dl_read; + up->dl_write = default_serial_dl_write; + + switch (p->iotype) { + case UPIO_HUB6: + p->serial_in = hub6_serial_in; + p->serial_out = hub6_serial_out; + break; + + case UPIO_MEM: + p->serial_in = mem_serial_in; + p->serial_out = mem_serial_out; + break; + + case UPIO_MEM32: + p->serial_in = mem32_serial_in; + p->serial_out = mem32_serial_out; + break; + +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) + case UPIO_AU: + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + up->dl_read = au_serial_dl_read; + up->dl_write = au_serial_dl_write; + break; +#endif + + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; + break; + } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; + p->handle_irq = serial8250_default_handle_irq; +} + +static void +serial_port_out_sync(struct uart_port *p, int offset, int value) +{ + switch (p->iotype) { + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + p->serial_out(p, offset, value); + p->serial_in(p, UART_LCR); /* safe, no side-effects */ + break; + default: + p->serial_out(p, offset, value); + } +} + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + +/* + * FIFO support. + */ +static void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(p, UART_FCR, 0); + } +} + +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + unsigned char fcr; + + serial8250_clear_fifos(p); + fcr = uart_config[p->port.type].fcr; + serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + /* + * Exar UARTs have a SLEEP register that enables or disables + * each UART to enter sleep mode separately. On the XR17V35x the + * register is accessible to each UART at the UART_EXAR_SLEEP + * offset but the UART channel may only write to the corresponding + * bit. + */ + if ((p->port.type == PORT_XR17V35X) || + (p->port.type == PORT_XR17D15X)) { + serial_out(p, UART_EXAR_SLEEP, 0xff); + return; + } + + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, 0); + serial_out(p, UART_LCR, 0); + } + } +} + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_8250_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_out(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct uart_8250_port *up) +{ + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; + int count; + + old_lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, 0); + old_fcr = serial_in(up, UART_FCR); + old_mcr = serial_in(up, UART_MCR); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_MCR, UART_MCR_LOOP); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); + serial_out(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_out(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ + for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_in(up, UART_RX); + serial_out(up, UART_FCR, old_fcr); + serial_out(up, UART_MCR, old_mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_dl_write(up, old_dl); + serial_out(up, UART_LCR, old_lcr); + + return count; +} + +/* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We + * preserve the device state across this. + */ +static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) +{ + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + + old_lcr = serial_in(p, UART_LCR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + + old_dll = serial_in(p, UART_DLL); + old_dlm = serial_in(p, UART_DLM); + + serial_out(p, UART_DLL, 0); + serial_out(p, UART_DLM, 0); + + id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; + + serial_out(p, UART_DLL, old_dll); + serial_out(p, UART_DLM, old_dlm); + serial_out(p, UART_LCR, old_lcr); + + return id; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_has_efr(struct uart_8250_port *up) +{ + unsigned int id1, id2, id3, rev; + + /* + * Everything with an EFR has SLEEP + */ + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + + /* + * Check for Oxford Semiconductor 16C950. + * + * EFR [4] must be set else this test fails. + * + * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) + * claims that it's needed for 952 dual UART's (which are not + * recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0x00); + id1 = serial_icr_read(up, UART_ID1); + id2 = serial_icr_read(up, UART_ID2); + id3 = serial_icr_read(up, UART_ID3); + rev = serial_icr_read(up, UART_REV); + + DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); + + if (id1 == 0x16 && id2 == 0xC9 && + (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { + up->port.type = PORT_16C950; + + /* + * Enable work around for the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if (id3 == 0x52 && rev == 0x01) + up->bugs |= UART_BUG_QUOT; + return; + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and then + * reading back DLL and DLM. The chip type depends on the DLM + * value read back: + * 0x10 - XR16C850 and the DLL contains the chip revision. + * 0x12 - XR16C2850. + * 0x14 - XR16C854. + */ + id1 = autoconfig_read_divisor_id(up); + DEBUG_AUTOCONF("850id=%04x ", id1); + + id2 = id1 >> 8; + if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { + up->port.type = PORT_16850; + return; + } + + /* + * It wasn't an XR16C850. + * + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(up) == 64) + up->port.type = PORT_16654; + else + up->port.type = PORT_16650V2; +} + +/* + * We detected a chip without a FIFO. Only two fall into + * this category - the original 8250 and the 16450. The + * 16450 has a scratch register (accessible with LCR=0) + */ +static void autoconfig_8250(struct uart_8250_port *up) +{ + unsigned char scratch, status1, status2; + + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +} + +static int broken_efr(struct uart_8250_port *up) +{ + /* + * Exar ST16C2550 "A2" devices incorrectly detect as + * having an EFR, and report an ID of 0x0201. See + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + */ + if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) + return 1; + + return 0; +} + +static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) +{ + unsigned char status; + + status = serial_in(up, 0x04); /* EXCR2 */ +#define PRESL(x) ((x) & 0x30) + if (PRESL(status) == 0x10) { + /* already in high speed mode */ + return 0; + } else { + status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ + serial_out(up, 0x04, status); + } + return 1; +} + +/* + * We know that the chip has FIFOs. Does it have an EFR? The + * EFR is located in the same register position as the IIR and + * we know the top two bits of the IIR are currently set. The + * EFR should contain zero. Try to read the EFR. + */ +static void autoconfig_16550a(struct uart_8250_port *up) +{ + unsigned char status1, status2; + unsigned int iersave; + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; + + /* + * XR17V35x UARTs have an extra divisor register, DLD + * that gets enabled with when DLAB is set which will + * cause the device to incorrectly match and assign + * port type to PORT_16650. The EFR for this UART is + * found at offset 0x09. Instead check the Deice ID (DVID) + * register for a 2, 4 or 8 port UART. + */ + if (up->port.flags & UPF_EXAR_EFR) { + status1 = serial_in(up, UART_EXAR_DVID); + if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { + DEBUG_AUTOCONF("Exar XR17V35x "); + up->port.type = PORT_XR17V35X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + } + + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + if (serial_in(up, UART_EFR) == 0) { + serial_out(up, UART_EFR, 0xA8); + if (serial_in(up, UART_EFR) != 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + } else { + DEBUG_AUTOCONF("Motorola 8xxx DUART "); + } + serial_out(up, UART_EFR, 0); + return; + } + + /* + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); + return; + } + + /* + * Check for a National Semiconductor SuperIO chip. + * Attempt to switch to bank 2, read the value of the LOOP bit + * from EXCR1. Switch back to bank 0, change it in MCR. Then + * switch back to bank 2, read it from EXCR1 again and check + * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 + */ + serial_out(up, UART_LCR, 0); + status1 = serial_in(up, UART_MCR); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + + if (!((status2 ^ status1) & UART_MCR_LOOP)) { + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1); + + if ((status2 ^ status1) & UART_MCR_LOOP) { + unsigned short quot; + + serial_out(up, UART_LCR, 0xE0); + + quot = serial_dl_read(up); + quot <<= 3; + + if (ns16550a_goto_highspeed(up)) + serial_dl_write(up, quot); + + serial_out(up, UART_LCR, 0); + + up->port.uartclk = 921600*16; + up->port.type = PORT_NS16550A; + up->capabilities |= UART_NATSEMI; + return; + } + } + + /* + * No EFR. Try to detect a TI16750, which only sets bit 5 of + * the IIR when 64 byte FIFO mode is enabled when DLAB is set. + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + + if (status1 == 6 && status2 == 7) { + up->port.type = PORT_16750; + up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; + return; + } + + /* + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + iersave = serial_in(up, UART_IER); + serial_out(up, UART_IER, iersave & ~UART_IER_UUE); + if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + serial_out(up, UART_IER, iersave | UART_IER_UUE); + if (serial_in(up, UART_IER) & UART_IER_UUE) { + /* + * It's an Xscale. + * We'll leave the UART_IER_UUE bit set to 1 (enabled). + */ + DEBUG_AUTOCONF("Xscale "); + up->port.type = PORT_XSCALE; + up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; + return; + } + } else { + /* + * If we got here we couldn't force the IER_UUE bit to 0. + * Log it and continue. + */ + DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); + } + serial_out(up, UART_IER, iersave); + + /* + * Exar uarts have EFR in a weird location + */ + if (up->port.flags & UPF_EXAR_EFR) { + DEBUG_AUTOCONF("Exar XR17D15x "); + up->port.type = PORT_XR17D15X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. + */ + if (up->port.type == PORT_16550A && size_fifo(up) == 64) { + up->port.type = PORT_U6_16550A; + up->capabilities |= UART_CAP_AFE; + } +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +{ + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int old_capabilities; + + if (!port->iobase && !port->mapbase && !port->membase) + return; + + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", + serial_index(port), port->iobase, port->membase); + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ + spin_lock_irqsave(&port->lock, flags); + + up->capabilities = 0; + up->bugs = 0; + + if (!(port->flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + * + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. + */ + scratch = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here + */ + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); + goto out; + } + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(port->flags & UPF_SKIP_TEST)) { + serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_in(up, UART_MSR) & 0xF0; + serial_out(up, UART_MCR, save_mcr); + if (status1 != 0x90) { + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); + goto out; + } + } + + /* + * We're pretty sure there's a port here. Lets find out what + * type of port it is. The IIR top two bits allows us to find + * out if it's 8250 or 16450, 16550, 16550A or later. This + * determines what we test for next. + * + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, 0); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + + switch (scratch) { + case 0: + autoconfig_8250(up); + break; + case 1: + port->type = PORT_UNKNOWN; + break; + case 2: + port->type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); + break; + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Only probe for RSA ports if we got the region. + */ + if (port->type == PORT_16550A && probeflags & PROBE_RSA) { + int i; + + for (i = 0 ; i < probe_rsa_count; ++i) { + if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { + port->type = PORT_RSA; + break; + } + } + } +#endif + + serial_out(up, UART_LCR, save_lcr); + + port->fifosize = uart_config[up->port.type].fifo_size; + old_capabilities = up->capabilities; + up->capabilities = uart_config[port->type].flags; + up->tx_loadsz = uart_config[port->type].tx_loadsz; + + if (port->type == PORT_UNKNOWN) + goto out_lock; + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (port->type == PORT_RSA) + serial_out(up, UART_RSA_FRR, 0); +#endif + serial_out(up, UART_MCR, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + +out_lock: + spin_unlock_irqrestore(&port->lock, flags); + if (up->capabilities != old_capabilities) { + printk(KERN_WARNING + "ttyS%d: detected caps %08x should be %08x\n", + serial_index(port), old_capabilities, + up->capabilities); + } +out: + DEBUG_AUTOCONF("iir=%d ", scratch); + DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); +} + +static void autoconfig_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + + if (port->flags & UPF_FOURPORT) { + ICP = (port->iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + inb_p(ICP); + } + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_in(up, UART_MCR); + save_ier = serial_in(up, UART_IER); + serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_out(up, UART_MCR, 0); + udelay(10); + if (port->flags & UPF_FOURPORT) { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_out(up, UART_IER, 0x0f); /* enable all intrs */ + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); + serial_out(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); + + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_IER, save_ier); + + if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + + port->irq = (irq > 0) ? irq : 0; +} + +static inline void __stop_tx(struct uart_8250_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } +} + +static void serial8250_stop_tx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + __stop_tx(up); + + /* + * We really want to stop the transmitter from sending. + */ + if (port->type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_start_tx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + if (up->dma && !serial8250_tx_dma(up)) { + return; + } else if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_port_out(port, UART_IER, up->ier); + + if (up->bugs & UART_BUG_TXEN) { + unsigned char lsr; + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (lsr & UART_LSR_TEMT) + serial8250_tx_chars(up); + } + } + + /* + * Re-enable the transmitter if we disabled it. + */ + if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_port_out(port, UART_IER, up->ier); +} + +static void serial8250_enable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier |= UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +} + +/* + * serial8250_rx_chars: processes according to the passed in LSR + * value, and returns the remaining LSR bits not handled + * by this Rx routine. + */ +unsigned char +serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +{ + struct uart_port *port = &up->port; + unsigned char ch; + int max_count = 256; + char flag; + + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will + * set UART_LSR_BI without setting UART_LSR_DR when + * it receives a break. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we + * just force the read character to be 0 + */ + ch = 0; + + flag = TTY_NORMAL; + port->icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; + + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) + port->icount.parity++; + else if (lsr & UART_LSR_FE) + port->icount.frame++; + if (lsr & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + lsr &= port->read_status_mask; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + flag = TTY_BREAK; + } else if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); + +ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); + return lsr; +} +EXPORT_SYMBOL_GPL(serial8250_rx_chars); + +void serial8250_tx_chars(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + struct circ_buf *xmit = &port->state->xmit; + int count; + + if (port->x_char) { + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_tx_stopped(port)) { + serial8250_stop_tx(port); + return; + } + if (uart_circ_empty(xmit)) { + __stop_tx(up); + return; + } + + count = up->tx_loadsz; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + if (up->capabilities & UART_CAP_HFIFO) { + if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != + BOTH_EMPTY) + break; + } + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + DEBUG_INTR("THRE..."); + + if (uart_circ_empty(xmit)) + __stop_tx(up); +} +EXPORT_SYMBOL_GPL(serial8250_tx_chars); + +unsigned int serial8250_modem_status(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned int status = serial_in(up, UART_MSR); + + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + port->state != NULL) { + if (status & UART_MSR_TERI) + port->icount.rng++; + if (status & UART_MSR_DDSR) + port->icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(port, status & UART_MSR_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + return status; +} +EXPORT_SYMBOL_GPL(serial8250_modem_status); + +/* + * This handles the interrupt from one port. + */ +int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +{ + unsigned char status; + unsigned long flags; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + int dma_err = 0; + + if (iir & UART_IIR_NO_INT) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (up->dma) + dma_err = serial8250_rx_dma(up, iir); + + if (!up->dma || dma_err) + status = serial8250_rx_chars(up, status); + } + serial8250_modem_status(up); + if (status & UART_LSR_THRE) + serial8250_tx_chars(up); + + spin_unlock_irqrestore(&port->lock, flags); + return 1; +} +EXPORT_SYMBOL_GPL(serial8250_handle_irq); + +static int serial8250_default_handle_irq(struct uart_port *port) +{ + unsigned int iir = serial_port_in(port, UART_IIR); + + return serial8250_handle_irq(port, iir); +} + +/* + * These Exar UARTs have an extra interrupt indicator that could + * fire for a few unimplemented interrupts. One of which is a + * wakeup event when coming out of sleep. Put this here just + * to be on the safe side that these interrupts don't go unhandled. + */ +static int exar_handle_irq(struct uart_port *port) +{ + unsigned char int0, int1, int2, int3; + unsigned int iir = serial_port_in(port, UART_IIR); + int ret; + + ret = serial8250_handle_irq(port, iir); + + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) { + int0 = serial_port_in(port, 0x80); + int1 = serial_port_in(port, 0x81); + int2 = serial_port_in(port, 0x82); + int3 = serial_port_in(port, 0x83); + } + + return ret; +} + +/* + * This is the serial driver's interrupt routine. + * + * Arjan thinks the old way was overly complex, so it got simplified. + * Alan disagrees, saying that need the complexity to handle the weird + * nature of ISA shared interrupts. (This is a special exception.) + * + * In order to handle ISA shared interrupts properly, we need to check + * that all ports have been serviced, and therefore the ISA interrupt + * line has been de-asserted. + * + * This means we need to loop through all ports. checking that they + * don't have an interrupt pending. + */ +static irqreturn_t serial8250_interrupt(int irq, void *dev_id) +{ + struct irq_info *i = dev_id; + struct list_head *l, *end = NULL; + int pass_counter = 0, handled = 0; + + DEBUG_INTR("serial8250_interrupt(%d)...", irq); + + spin_lock(&i->lock); + + l = i->head; + do { + struct uart_8250_port *up; + struct uart_port *port; + + up = list_entry(l, struct uart_8250_port, list); + port = &up->port; + + if (port->handle_irq(port)) { + handled = 1; + end = NULL; + } else if (end == NULL) + end = l; + + l = l->next; + + if (l == i->head && pass_counter++ > PASS_LIMIT) { + /* If we hit this, we're dead. */ + printk_ratelimited(KERN_ERR + "serial8250: too much work for irq%d\n", irq); + break; + } + } while (l != end); + + spin_unlock(&i->lock); + + DEBUG_INTR("end.\n"); + + return IRQ_RETVAL(handled); +} + +/* + * To support ISA shared interrupts, we need to have one interrupt + * handler that ensures that the IRQ line has been deasserted + * before returning. Failing to do this will result in the IRQ + * line being stuck active, and, since ISA irqs are edge triggered, + * no more IRQs will be seen. + */ +static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) +{ + spin_lock_irq(&i->lock); + + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + spin_unlock_irq(&i->lock); + /* List empty so throw away the hash node */ + if (i->head == NULL) { + hlist_del(&i->node); + kfree(i); + } +} + +static int serial_link_irq_chain(struct uart_8250_port *up) +{ + struct hlist_head *h; + struct hlist_node *n; + struct irq_info *i; + int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; + + mutex_lock(&hash_mutex); + + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; + } + + if (n == NULL) { + i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); + if (i == NULL) { + mutex_unlock(&hash_mutex); + return -ENOMEM; + } + spin_lock_init(&i->lock); + i->irq = up->port.irq; + hlist_add_head(&i->node, h); + } + mutex_unlock(&hash_mutex); + + spin_lock_irq(&i->lock); + + if (i->head) { + list_add(&up->list, i->head); + spin_unlock_irq(&i->lock); + + ret = 0; + } else { + INIT_LIST_HEAD(&up->list); + i->head = &up->list; + spin_unlock_irq(&i->lock); + irq_flags |= up->port.irqflags; + ret = request_irq(up->port.irq, serial8250_interrupt, + irq_flags, "serial", i); + if (ret < 0) + serial_do_unlink(i, up); + } + + return ret; +} + +static void serial_unlink_irq_chain(struct uart_8250_port *up) +{ + struct irq_info *i; + struct hlist_node *n; + struct hlist_head *h; + + mutex_lock(&hash_mutex); + + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; + } + + BUG_ON(n == NULL); + BUG_ON(i->head == NULL); + + if (list_empty(i->head)) + free_irq(up->port.irq, i); + + serial_do_unlink(i, up); + mutex_unlock(&hash_mutex); +} + +/* + * This function is used to handle ports that do not have an + * interrupt. This doesn't work very well for 16450's, but gives + * barely passable results for a 16550A. (Although at the expense + * of much CPU overhead). + */ +static void serial8250_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + + up->port.handle_irq(&up->port); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); +} + +static void serial8250_backup_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int iir, ier = 0, lsr; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Must disable interrupts or else we risk racing with the interrupt + * based handler. + */ + if (up->port.irq) { + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + } + + iir = serial_in(up, UART_IIR); + + /* + * This should be a safe test for anyone who doesn't trust the + * IIR bits on their UART, but it's specifically designed for + * the "Diva" UART used on the management processor on many HP + * ia64 and parisc boxes. + */ + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && + (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (lsr & UART_LSR_THRE)) { + iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); + iir |= UART_IIR_THRI; + } + + if (!(iir & UART_IIR_NO_INT)) + serial8250_tx_chars(up); + + if (up->port.irq) + serial_out(up, UART_IER, ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + + /* Standard timer interval plus 0.2s to keep the port running */ + mod_timer(&up->timer, + jiffies + uart_poll_timeout(&up->port) + HZ / 5); +} + +static unsigned int serial8250_tx_empty(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + unsigned int lsr; + + spin_lock_irqsave(&port->lock, flags); + lsr = serial_port_in(port, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&port->lock, flags); + + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned int status; + unsigned int ret; + + status = serial8250_modem_status(up); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + + serial_port_out(port, UART_MCR, mcr); +} + +static void serial8250_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_port_out(port, UART_LCR, up->lcr); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + for (;;) { + status = serial_in(up, UART_LSR); + + up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + + if ((status & bits) == bits) + break; + if (--tmout == 0) + break; + udelay(1); + } + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + unsigned int tmout; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + udelay(1); + touch_nmi_watchdog(); + } + } +} + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + unsigned char lsr = serial_port_in(port, UART_LSR); + + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; + + return serial_port_in(port, UART_RX); +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_port_out(port, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_TX, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +static int serial8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + unsigned char lsr, iir; + int retval; + + if (port->type == PORT_8250_CIR) + return -ENODEV; + + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; + up->mcr = 0; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + if (port->type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial8250_clear_fifos(up); + + /* + * Clear the interrupt registers. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(port->flags & UPF_BUGGY_UART) && + (serial_port_in(port, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(port)); + return -ENODEV; + } + + /* + * For a XR16C850, we need to set the trigger levels + */ + if (port->type == PORT_16850) { + unsigned char fctr; + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_port_out(port, UART_TRG, UART_TRG_96); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_port_out(port, UART_TRG, UART_TRG_96); + + serial_port_out(port, UART_LCR, 0); + } + + if (port->irq) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already + * been cleared. Real 16550s should always reassert + * this interrupt whenever the transmitter is idle and + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ + spin_lock_irqsave(&port->lock, flags); + if (up->port.irqflags & IRQF_SHARED) + disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir1 = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * If the interrupt is not reasserted, or we otherwise + * don't trust the iir, setup a timer to kick the UART + * on a regular basis. + */ + if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || + up->port.flags & UPF_BUG_THRE) { + up->bugs |= UART_BUG_THRE; + pr_debug("ttyS%d - using backup timer\n", + serial_index(port)); + } + } + + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else { + retval = serial_link_irq_chain(up); + if (retval) + return retval; + } + + /* + * Now, initialize the UART + */ + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&port->lock, flags); + if (up->port.flags & UPF_FOURPORT) { + if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + if (port->irq) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + + /* Serial over Lan (SoL) hack: + Intel 8257x Gigabit ethernet chips have a + 16550 emulation, to be used for Serial Over Lan. + Those chips take a longer time than a normal + serial device to signalize that a transmission + data was queued. Due to that, the above test generally + fails. One solution would be to delay the reading of + iir. However, this is not reliable, since the timeout + is variable. So, let's just don't test if we receive + TX irq. This way, we'll never enable UART_BUG_TXEN. + */ + if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) + goto dont_test_tx_en; + + /* + * Do a quick test to see if we receive an + * interrupt when we enable the TX irq. + */ + serial_port_out(port, UART_IER, UART_IER_THRI); + lsr = serial_port_in(port, UART_LSR); + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { + up->bugs |= UART_BUG_TXEN; + pr_debug("ttyS%d - enabling bad tx status workarounds\n", + serial_index(port)); + } + } else { + up->bugs &= ~UART_BUG_TXEN; + } + +dont_test_tx_en: + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Clear the interrupt registers again for luck, and clear the + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + + /* + * Request DMA channels for both RX and TX. + */ + if (up->dma) { + retval = serial8250_request_dma(up); + if (retval) { + pr_warn_ratelimited("ttyS%d - failed to request DMA\n", + serial_index(port)); + up->dma = NULL; + } + } + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_port_out(port, UART_IER, up->ier); + + if (port->flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (port->iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + inb_p(icp); + } + + return 0; +} + +static void serial8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_port_out(port, UART_IER, 0); + + if (up->dma) + serial8250_release_dma(up); + + spin_lock_irqsave(&port->lock, flags); + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; + } else + port->mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_port_out(port, UART_LCR, + serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ + serial_port_in(port, UART_RX); + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); +} + +static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) +{ + unsigned int quot; + + /* + * Handle magic divisors for baud rates above baud_base on + * SMSC SuperIO chips. + */ + if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/4)) + quot = 0x8001; + else if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/8)) + quot = 0x8002; + else + quot = uart_get_divisor(port, baud); + + return quot; +} + +void +serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned char cval, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + int fifo_bug = 0; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) { + cval |= UART_LCR_PARITY; + if (up->bugs & UART_BUG_PARITY) + fifo_bug = 1; + } + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); + quot = serial8250_get_divisor(port, baud); + + /* + * Oxford Semi 952 rev B workaround + */ + if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) + quot++; + + if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { + fcr = uart_config[port->type].fcr; + if (baud < 2400 || fifo_bug) { + fcr &= ~UART_FCR_TRIGGER_MASK; + fcr |= UART_FCR_TRIGGER_1; + } + } + + /* + * MCR-based auto flow control. When AFE is enabled, RTS will be + * deasserted when the receive FIFO contains more characters than + * the trigger, or the MCR RTS bit is cleared. In the case where + * the remote UART is not using CTS auto flow control, we must + * have sufficient FIFO entries for the latency of the remote + * UART to respond. IOW, at least 32 bytes of FIFO. + */ + if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + } + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (!(up->bugs & UART_BUG_NOMSR) && + UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + if (up->capabilities & UART_CAP_UUE) + up->ier |= UART_IER_UUE; + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + + serial_port_out(port, UART_IER, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; + /* + * TI16C752/Startech hardware flow control. FIXME: + * - TI16C752 requires control thresholds to be set. + * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. + */ + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + if (port->flags & UPF_EXAR_EFR) + serial_port_out(port, UART_XR_EFR, efr); + else + serial_port_out(port, UART_EFR, efr); + } + + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (is_omap1510_8250(up)) { + if (baud == 115200) { + quot = 1; + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); + } else + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); + } + + /* + * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, + * otherwise just set DLAB + */ + if (up->capabilities & UART_NATSEMI) + serial_port_out(port, UART_LCR, 0xe0); + else + serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB); + + serial_dl_write(up, quot); + + /* + * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR + * is written without DLAB set, this mode will be disabled. + */ + if (port->type == PORT_16750) + serial_port_out(port, UART_FCR, fcr); + + serial_port_out(port, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (port->type != PORT_16750) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + if (fcr & UART_FCR_ENABLE_FIFO) + serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_port_out(port, UART_FCR, fcr); /* set fcr */ + } + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} +EXPORT_SYMBOL(serial8250_do_set_termios); + +static void +serial8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + if (port->set_termios) + port->set_termios(port, termios, old); + else + serial8250_do_set_termios(port, termios, old); +} + +static void +serial8250_set_ldisc(struct uart_port *port, int new) +{ + if (new == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + serial8250_enable_ms(port); + } else + port->flags &= ~UPF_HARDPPS_CD; +} + + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *p = + container_of(port, struct uart_8250_port, port); + + serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); + +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); +} + +static unsigned int serial8250_port_size(struct uart_8250_port *pt) +{ + if (pt->port.iotype == UPIO_AU) + return 0x1000; + if (is_omap1_8250(pt)) + return 0x16 << pt->port.regshift; + + return 8 << pt->port.regshift; +} + +/* + * Resource handling. + */ +static int serial8250_request_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; + int ret = 0; + + switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (!request_mem_region(port->mapbase, size, "serial")) { + ret = -EBUSY; + break; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); + ret = -ENOMEM; + } + } + break; + + case UPIO_HUB6: + case UPIO_PORT: + if (!request_region(port->iobase, size, "serial")) + ret = -EBUSY; + break; + } + return ret; +} + +static void serial8250_release_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; + + switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); + break; + + case UPIO_HUB6: + case UPIO_PORT: + release_region(port->iobase, size); + break; + } +} + +static int serial8250_request_rsa_resource(struct uart_8250_port *up) +{ + unsigned long start = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; + struct uart_port *port = &up->port; + int ret = -EINVAL; + + switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: + start += port->iobase; + if (request_region(start, size, "serial-rsa")) + ret = 0; + else + ret = -EBUSY; + break; + } + + return ret; +} + +static void serial8250_release_rsa_resource(struct uart_8250_port *up) +{ + unsigned long offset = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; + struct uart_port *port = &up->port; + + switch (port->iotype) { + case UPIO_HUB6: + case UPIO_PORT: + release_region(port->iobase + offset, size); + break; + } +} + +static void serial8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + serial8250_release_std_resource(up); + if (port->type == PORT_RSA) + serial8250_release_rsa_resource(up); +} + +static int serial8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + int ret; + + if (port->type == PORT_8250_CIR) + return -ENODEV; + + ret = serial8250_request_std_resource(up); + if (ret == 0 && port->type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + serial8250_release_std_resource(up); + } + + return ret; +} + +static void serial8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + int probeflags = PROBE_ANY; + int ret; + + if (port->type == PORT_8250_CIR) + return; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial8250_request_std_resource(up); + if (ret < 0) + return; + + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + probeflags &= ~PROBE_RSA; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + if (flags & UART_CONFIG_TYPE) + autoconfig(up, probeflags); + + /* if access method is AU, it is a 16550 with a quirk */ + if (port->type == PORT_16550A && port->iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; + + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + + if (port->type != PORT_RSA && probeflags & PROBE_RSA) + serial8250_release_rsa_resource(up); + if (port->type == PORT_UNKNOWN) + serial8250_release_std_resource(up); + + /* Fixme: probably not the best place for this */ + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) + port->handle_irq = exar_handle_irq; +} + +static int +serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->irq >= nr_irqs || ser->irq < 0 || + ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || + ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || + ser->type == PORT_STARTECH) + return -EINVAL; + return 0; +} + +static const char * +serial8250_type(struct uart_port *port) +{ + int type = port->type; + + if (type >= ARRAY_SIZE(uart_config)) + type = 0; + return uart_config[type].name; +} + +static struct uart_ops serial8250_pops = { + .tx_empty = serial8250_tx_empty, + .set_mctrl = serial8250_set_mctrl, + .get_mctrl = serial8250_get_mctrl, + .stop_tx = serial8250_stop_tx, + .start_tx = serial8250_start_tx, + .stop_rx = serial8250_stop_rx, + .enable_ms = serial8250_enable_ms, + .break_ctl = serial8250_break_ctl, + .startup = serial8250_startup, + .shutdown = serial8250_shutdown, + .set_termios = serial8250_set_termios, + .set_ldisc = serial8250_set_ldisc, + .pm = serial8250_pm, + .type = serial8250_type, + .release_port = serial8250_release_port, + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif +}; + +static struct uart_8250_port serial8250_ports[UART_NR]; + +static void (*serial8250_isa_config)(int port, struct uart_port *up, + unsigned short *capabilities); + +void serial8250_set_isa_configurator( + void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) +{ + serial8250_isa_config = v; +} +EXPORT_SYMBOL(serial8250_set_isa_configurator); + +static void __init serial8250_isa_init_ports(void) +{ + struct uart_8250_port *up; + static int first = 1; + int i, irqflag = 0; + + if (!first) + return; + first = 0; + + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + struct uart_port *port = &up->port; + + port->line = i; + spin_lock_init(&port->lock); + + init_timer(&up->timer); + up->timer.function = serial8250_timeout; + up->cur_iotype = 0xFF; + + /* + * ALPHA_KLUDGE_MCR needs to be killed. + */ + up->mcr_mask = ~ALPHA_KLUDGE_MCR; + up->mcr_force = ALPHA_KLUDGE_MCR; + + port->ops = &serial8250_pops; + } + + if (share_irqs) + irqflag = IRQF_SHARED; + + for (i = 0, up = serial8250_ports; + i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; + i++, up++) { + struct uart_port *port = &up->port; + + port->iobase = old_serial_port[i].port; + port->irq = irq_canonicalize(old_serial_port[i].irq); + port->irqflags = old_serial_port[i].irqflags; + port->uartclk = old_serial_port[i].baud_base * 16; + port->flags = old_serial_port[i].flags; + port->hub6 = old_serial_port[i].hub6; + port->membase = old_serial_port[i].iomem_base; + port->iotype = old_serial_port[i].io_type; + port->regshift = old_serial_port[i].iomem_reg_shift; + set_io_from_upio(port); + port->irqflags |= irqflag; + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + + } +} + +static void +serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) +{ + up->port.type = type; + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; +} + +static void __init +serial8250_register_ports(struct uart_driver *drv, struct device *dev) +{ + int i; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.dev) + continue; + + up->port.dev = dev; + + if (up->port.flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(up, up->port.type); + + uart_add_one_port(drv, &up->port); + } +} + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +static void serial8250_console_putchar(struct uart_port *port, int ch) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out(port, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +serial8250_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier; + int locked = 1; + + touch_nmi_watchdog(); + + local_irq_save(flags); + if (port->sysrq) { + /* serial8250_handle_irq() already took the lock */ + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else + spin_lock(&port->lock); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + uart_console_write(port, s, count, serial8250_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); + + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + serial8250_modem_status(up); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static int __init serial8250_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= nr_uarts) + co->index = 0; + port = &serial8250_ports[co->index].port; + if (!port->iobase && !port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static int serial8250_console_early_setup(void) +{ + return serial8250_find_port_for_earlycon(); +} + +static struct console serial8250_console = { + .name = "ttyS", + .write = serial8250_console_write, + .device = uart_console_device, + .setup = serial8250_console_setup, + .early_setup = serial8250_console_early_setup, + .flags = CON_PRINTBUFFER | CON_ANYTIME, + .index = -1, + .data = &serial8250_reg, +}; + +static int __init serial8250_console_init(void) +{ + serial8250_isa_init_ports(); + register_console(&serial8250_console); + return 0; +} +console_initcall(serial8250_console_init); + +int serial8250_find_port(struct uart_port *p) +{ + int line; + struct uart_port *port; + + for (line = 0; line < nr_uarts; line++) { + port = &serial8250_ports[line].port; + if (uart_match_port(p, port)) + return line; + } + return -ENODEV; +} + +#define SERIAL8250_CONSOLE &serial8250_console +#else +#define SERIAL8250_CONSOLE NULL +#endif + +static struct uart_driver serial8250_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .cons = SERIAL8250_CONSOLE, +}; + +/* + * early_serial_setup - early registration for 8250 ports + * + * Setup an 8250 port structure prior to console initialisation. Use + * after console initialisation will cause undefined behaviour. + */ +int __init early_serial_setup(struct uart_port *port) +{ + struct uart_port *p; + + if (port->line >= ARRAY_SIZE(serial8250_ports)) + return -ENODEV; + + serial8250_isa_init_ports(); + p = &serial8250_ports[port->line].port; + p->iobase = port->iobase; + p->membase = port->membase; + p->irq = port->irq; + p->irqflags = port->irqflags; + p->uartclk = port->uartclk; + p->fifosize = port->fifosize; + p->regshift = port->regshift; + p->iotype = port->iotype; + p->flags = port->flags; + p->mapbase = port->mapbase; + p->private_data = port->private_data; + p->type = port->type; + p->line = port->line; + + set_io_from_upio(p); + if (port->serial_in) + p->serial_in = port->serial_in; + if (port->serial_out) + p->serial_out = port->serial_out; + if (port->handle_irq) + p->handle_irq = port->handle_irq; + else + p->handle_irq = serial8250_default_handle_irq; + + return 0; +} + +/** + * serial8250_suspend_port - suspend one serial port + * @line: serial line number + * + * Suspend one serial port. + */ +void serial8250_suspend_port(int line) +{ + uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port); +} + +/** + * serial8250_resume_port - resume one serial port + * @line: serial line number + * + * Resume one serial port. + */ +void serial8250_resume_port(int line) +{ + struct uart_8250_port *up = &serial8250_ports[line]; + struct uart_port *port = &up->port; + + if (up->capabilities & UART_NATSEMI) { + /* Ensure it's still in high speed mode */ + serial_port_out(port, UART_LCR, 0xE0); + + ns16550a_goto_highspeed(up); + + serial_port_out(port, UART_LCR, 0); + port->uartclk = 921600*16; + } + uart_resume_port(&serial8250_reg, port); +} + +/* + * Register a set of serial devices attached to a platform device. The + * list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. + */ +static int serial8250_probe(struct platform_device *dev) +{ + struct plat_serial8250_port *p = dev->dev.platform_data; + struct uart_8250_port uart; + int ret, i, irqflag = 0; + + memset(&uart, 0, sizeof(uart)); + + if (share_irqs) + irqflag = IRQF_SHARED; + + for (i = 0; p && p->flags != 0; p++, i++) { + uart.port.iobase = p->iobase; + uart.port.membase = p->membase; + uart.port.irq = p->irq; + uart.port.irqflags = p->irqflags; + uart.port.uartclk = p->uartclk; + uart.port.regshift = p->regshift; + uart.port.iotype = p->iotype; + uart.port.flags = p->flags; + uart.port.mapbase = p->mapbase; + uart.port.hub6 = p->hub6; + uart.port.private_data = p->private_data; + uart.port.type = p->type; + uart.port.serial_in = p->serial_in; + uart.port.serial_out = p->serial_out; + uart.port.handle_irq = p->handle_irq; + uart.port.handle_break = p->handle_break; + uart.port.set_termios = p->set_termios; + uart.port.pm = p->pm; + uart.port.dev = &dev->dev; + uart.port.irqflags |= irqflag; + ret = serial8250_register_8250_port(&uart); + if (ret < 0) { + dev_err(&dev->dev, "unable to register port at index %d " + "(IO%lx MEM%llx IRQ%d): %d\n", i, + p->iobase, (unsigned long long)p->mapbase, + p->irq, ret); + } + } + return 0; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int serial8250_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.dev == &dev->dev) + serial8250_unregister_port(i); + } + return 0; +} + +static int serial8250_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_suspend_port(&serial8250_reg, &up->port); + } + + return 0; +} + +static int serial8250_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + serial8250_resume_port(i); + } + + return 0; +} + +static struct platform_driver serial8250_isa_driver = { + .probe = serial8250_probe, + .remove = serial8250_remove, + .suspend = serial8250_suspend, + .resume = serial8250_resume, + .driver = { + .name = "serial8250", + .owner = THIS_MODULE, + }, +}; + +/* + * This "device" covers _all_ ISA 8250-compatible serial devices listed + * in the table in include/asm/serial.h + */ +static struct platform_device *serial8250_isa_devs; + +/* + * serial8250_register_8250_port and serial8250_unregister_port allows for + * 16x50 serial ports to be configured at run-time, to support PCMCIA + * modems and PCI multiport cards. + */ +static DEFINE_MUTEX(serial_mutex); + +static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) +{ + int i; + + /* + * First, find a port entry which matches. + */ + for (i = 0; i < nr_uarts; i++) + if (uart_match_port(&serial8250_ports[i].port, port)) + return &serial8250_ports[i]; + + /* + * We didn't find a matching entry, so look for the first + * free entry. We look for one which hasn't been previously + * used (indicated by zero iobase). + */ + for (i = 0; i < nr_uarts; i++) + if (serial8250_ports[i].port.type == PORT_UNKNOWN && + serial8250_ports[i].port.iobase == 0) + return &serial8250_ports[i]; + + /* + * That also failed. Last resort is to find any entry which + * doesn't have a real port associated with it. + */ + for (i = 0; i < nr_uarts; i++) + if (serial8250_ports[i].port.type == PORT_UNKNOWN) + return &serial8250_ports[i]; + + return NULL; +} + +/** + * serial8250_register_8250_port - register a serial port + * @up: serial port template + * + * Configure the serial port specified by the request. If the + * port exists and is in use, it is hung up and unregistered + * first. + * + * The port is then probed and if necessary the IRQ is autodetected + * If this fails an error is returned. + * + * On success the port is ready to use and the line number is returned. + */ +int serial8250_register_8250_port(struct uart_8250_port *up) +{ + struct uart_8250_port *uart; + int ret = -ENOSPC; + + if (up->port.uartclk == 0) + return -EINVAL; + + mutex_lock(&serial_mutex); + + uart = serial8250_find_match_or_unused(&up->port); + if (uart && uart->port.type != PORT_8250_CIR) { + if (uart->port.dev) + uart_remove_one_port(&serial8250_reg, &uart->port); + + uart->port.iobase = up->port.iobase; + uart->port.membase = up->port.membase; + uart->port.irq = up->port.irq; + uart->port.irqflags = up->port.irqflags; + uart->port.uartclk = up->port.uartclk; + uart->port.fifosize = up->port.fifosize; + uart->port.regshift = up->port.regshift; + uart->port.iotype = up->port.iotype; + uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; + uart->bugs = up->bugs; + uart->port.mapbase = up->port.mapbase; + uart->port.private_data = up->port.private_data; + uart->port.fifosize = up->port.fifosize; + uart->tx_loadsz = up->tx_loadsz; + uart->capabilities = up->capabilities; + + if (up->port.dev) + uart->port.dev = up->port.dev; + + if (up->port.flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(uart, up->port.type); + + set_io_from_upio(&uart->port); + /* Possibly override default I/O functions. */ + if (up->port.serial_in) + uart->port.serial_in = up->port.serial_in; + if (up->port.serial_out) + uart->port.serial_out = up->port.serial_out; + if (up->port.handle_irq) + uart->port.handle_irq = up->port.handle_irq; + /* Possibly override set_termios call */ + if (up->port.set_termios) + uart->port.set_termios = up->port.set_termios; + if (up->port.pm) + uart->port.pm = up->port.pm; + if (up->port.handle_break) + uart->port.handle_break = up->port.handle_break; + if (up->dl_read) + uart->dl_read = up->dl_read; + if (up->dl_write) + uart->dl_write = up->dl_write; + if (up->dma) + uart->dma = up->dma; + + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); + + ret = uart_add_one_port(&serial8250_reg, &uart->port); + if (ret == 0) + ret = uart->port.line; + } + mutex_unlock(&serial_mutex); + + return ret; +} +EXPORT_SYMBOL(serial8250_register_8250_port); + +/** + * serial8250_unregister_port - remove a 16x50 serial port at runtime + * @line: serial line number + * + * Remove one serial port. This may not be called from interrupt + * context. We hand the port back to the our control. + */ +void serial8250_unregister_port(int line) +{ + struct uart_8250_port *uart = &serial8250_ports[line]; + + mutex_lock(&serial_mutex); + uart_remove_one_port(&serial8250_reg, &uart->port); + if (serial8250_isa_devs) { + 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; + } + mutex_unlock(&serial_mutex); +} +EXPORT_SYMBOL(serial8250_unregister_port); + +static int __init serial8250_init(void) +{ + int ret; + + serial8250_isa_init_ports(); + + printk(KERN_INFO "Serial: 8250/16550 driver, " + "%d ports, IRQ sharing %sabled\n", nr_uarts, + share_irqs ? "en" : "dis"); + +#ifdef CONFIG_SPARC + ret = sunserial_register_minors(&serial8250_reg, UART_NR); +#else + serial8250_reg.nr = UART_NR; + ret = uart_register_driver(&serial8250_reg); +#endif + if (ret) + goto out; + + ret = serial8250_pnp_init(); + if (ret) + goto unreg_uart_drv; + + serial8250_isa_devs = platform_device_alloc("serial8250", + PLAT8250_DEV_LEGACY); + if (!serial8250_isa_devs) { + ret = -ENOMEM; + goto unreg_pnp; + } + + ret = platform_device_add(serial8250_isa_devs); + if (ret) + goto put_dev; + + serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); + + ret = platform_driver_register(&serial8250_isa_driver); + if (ret == 0) + goto out; + + platform_device_del(serial8250_isa_devs); +put_dev: + platform_device_put(serial8250_isa_devs); +unreg_pnp: + serial8250_pnp_exit(); +unreg_uart_drv: +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +out: + return ret; +} + +static void __exit serial8250_exit(void) +{ + struct platform_device *isa_dev = serial8250_isa_devs; + + /* + * This tells serial8250_unregister_port() not to re-register + * the ports (thereby making serial8250_isa_driver permanently + * in use.) + */ + serial8250_isa_devs = NULL; + + platform_driver_unregister(&serial8250_isa_driver); + platform_device_unregister(isa_dev); + + serial8250_pnp_exit(); + +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +} + +module_init(serial8250_init); +module_exit(serial8250_exit); + +EXPORT_SYMBOL(serial8250_suspend_port); +EXPORT_SYMBOL(serial8250_resume_port); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); + +module_param(share_irqs, uint, 0644); +MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" + " (unsafe)"); + +module_param(nr_uarts, uint, 0644); +MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); + +module_param(skip_txen_test, uint, 0644); +MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); + +#ifdef CONFIG_SERIAL_8250_RSA +module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); +#endif +MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); + +#ifndef MODULE +/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name + * working as well for the module options so we don't break people. We + * need to keep the names identical and the convenient macros will happily + * refuse to let us do that by failing the build with redefinition errors + * of global variables. So we stick them inside a dummy function to avoid + * those conflicts. The options still get parsed, and the redefined + * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive. + * + * This is hacky. I'm sorry. + */ +static void __used s8250_options(void) +{ +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "8250_core." + + module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644); + module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644); + module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644); +#ifdef CONFIG_SERIAL_8250_RSA + __module_param_call(MODULE_PARAM_PREFIX, probe_rsa, + ¶m_array_ops, .arr = &__param_arr_probe_rsa, + 0444, -1); +#endif +} +#else +MODULE_ALIAS("8250_core"); +#endif diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index a23838a4d535..36d68d054307 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -2,10 +2,10 @@ # Makefile for the 8250 serial device drivers. # -obj-$(CONFIG_SERIAL_8250) += 8250_core.o -8250_core-y := 8250.o -8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o -8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +obj-$(CONFIG_SERIAL_8250) += 8250.o +8250-y := 8250_core.o +8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o -- cgit v1.2.3 From 9326b047e4fd4a8da72e59d913214a1803e9709c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 19 Mar 2013 11:34:57 +0100 Subject: TTY: 8250, deprecated 8250_core.* options They were introduced by mistake in 3.7. Let's deprecate them now. For the reasons, see the text in Kconfig below. Signed-off-by: Jiri Slaby Cc: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 2 ++ drivers/tty/serial/8250/Kconfig | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 2d563cb9057e..35f9c96aada9 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -3418,6 +3418,7 @@ MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); #endif MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); +#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS #ifndef MODULE /* This module was renamed to 8250_core in 3.7. Keep the old "8250" name * working as well for the module options so we don't break people. We @@ -3446,3 +3447,4 @@ static void __used s8250_options(void) #else MODULE_ALIAS("8250_core"); #endif +#endif diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 2ef9537bcb2c..80fe91e64a52 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -33,6 +33,23 @@ config SERIAL_8250 Most people will say Y or M here, so that they can use serial mice, modems and similar devices connecting to the standard serial ports. +config SERIAL_8250_DEPRECATED_OPTIONS + bool "Support 8250_core.* kernel options (DEPRECATED)" + depends on SERIAL_8250 + default y + ---help--- + In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to + accept kernel parameters in both forms like 8250_core.nr_uarts=4 and + 8250.nr_uarts=4. We now renamed the module back to 8250, but if + anybody noticed in 3.7 and changed their userspace we still have to + keep the 8350_core.* options around until they revert the changes + they already did. + + If 8250 is built as a module, this adds 8250_core alias instead. + + If you did not notice yet and/or you have userspace from pre-3.7, it + is safe (and recommended) to say N here. + config SERIAL_8250_PNP bool "8250/16550 PNP device support" if EXPERT depends on SERIAL_8250 && PNP -- cgit v1.2.3 From 855f6fd941019ecc9525ca038b78f50c6c1e80a8 Mon Sep 17 00:00:00 2001 From: John Linn Date: Fri, 22 Mar 2013 18:49:27 +0100 Subject: Xilinx: ARM: UART: clear pending irqs before enabling irqs The Boot ROM has an issue which will cause the driver to lock up as pending irqs are not being cleared. With them cleared it prevents that issue. This patch is needed for the current (3.9-rc3) mainline kernel. I guess it went unnoticed, because it was only tested with u-boot up until now. And u-boot maybe handles this. [s.trumtrar@pengutronix.de: cherry-picked from linux-xlnx.git] Signed-off-by: Steffen Trumtrar Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index ba451c7209fc..f36bbba1ac8b 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -578,6 +578,8 @@ static int xuartps_startup(struct uart_port *port) /* Receive Timeout register is enabled with value of 10 */ xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + /* Clear out any pending interrupts before enabling them */ + xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | -- cgit v1.2.3 From d8d595dfce7925627de78b9eecc8598a6ffda610 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Mon, 25 Mar 2013 19:22:31 -0600 Subject: block: removes dynamic allocation on stack This patch removes dynamic allocation on the stack error. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/dma.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index d523e9c56578..95047e111a33 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -986,7 +986,10 @@ void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) int j; int cnt; struct rsxx_dma *dma; - struct list_head issued_dmas[card->n_targets]; + struct list_head *issued_dmas; + + issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets, + GFP_KERNEL); for (i = 0; i < card->n_targets; i++) { INIT_LIST_HEAD(&issued_dmas[i]); @@ -1025,6 +1028,8 @@ void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) } spin_unlock(&card->ctrl[i].queue_lock); } + + kfree(issued_dmas); } void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card) -- cgit v1.2.3 From bd17381372c0740c43a9addf0d80271f647f2b38 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 25 Mar 2013 11:24:10 +0100 Subject: drm/i915: duct-tape locking when eDP init fails Thanks to apple gpu mux fail we detect an eDP output, but can't read anything over dp aux. In the resulting failure path we then hit a paranoid WARN about potential locking. Since the WARN is pretty useful for normal operation just paper over it in the failure case by grabbing the demanded (but for init/teardown not really required) lock. I've checked our driver unload code and we already don't hold the kms lock when calling drm_mode_config_cleanup. So this won't lead to a new deadlock when reloading i915.ko. v2: Make it compile. Reported-by: Dave Airlie Cc: Dave Airlie Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d7d4afe01341..8fc93f90a7cd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2559,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; + struct drm_device *dev = intel_dp_to_dev(intel_dp); i2c_del_adapter(&intel_dp->adapter); drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->mode_config.mutex); } kfree(intel_dig_port); } -- cgit v1.2.3 From a1f6c6b147cc5e83ec36dab8370bd5ec5fa1def6 Mon Sep 17 00:00:00 2001 From: xunleer Date: Tue, 5 Mar 2013 07:44:20 +0000 Subject: ixgbevf: don't release the soft entries When the ixgbevf driver is opened the request to allocate MSIX irq vectors may fail. In that case the driver will call ixgbevf_down() which will call ixgbevf_irq_disable() to clear the HW interrupt registers and calls synchronize_irq() using the msix_entries pointer in the adapter structure. However, when the function to request the MSIX irq vectors failed it had already freed the msix_entries which causes an OOPs from using the NULL pointer in synchronize_irq(). The calls to pci_disable_msix() and to free the msix_entries memory should not occur if device open fails. Instead they should be called during device driver removal to balance with the call to pci_enable_msix() and the call to allocate msix_entries memory during the device probe and driver load. Signed-off-by: Li Xun Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index c3db6cd69b68..2b6cb5ca48ee 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -944,9 +944,17 @@ free_queue_irqs: free_irq(adapter->msix_entries[vector].vector, adapter->q_vector[vector]); } - pci_disable_msix(adapter->pdev); - kfree(adapter->msix_entries); - adapter->msix_entries = NULL; + /* This failure is non-recoverable - it indicates the system is + * out of MSIX vector resources and the VF driver cannot run + * without them. Set the number of msix vectors to zero + * indicating that not enough can be allocated. The error + * will be returned to the user indicating device open failed. + * Any further attempts to force the driver to open will also + * fail. The only way to recover is to unload the driver and + * reload it again. If the system has recovered some MSIX + * vectors then it may succeed. + */ + adapter->num_msix_vectors = 0; return err; } @@ -2572,6 +2580,15 @@ static int ixgbevf_open(struct net_device *netdev) struct ixgbe_hw *hw = &adapter->hw; int err; + /* A previous failure to open the device because of a lack of + * available MSIX vector resources may have reset the number + * of msix vectors variable to zero. The only way to recover + * is to unload/reload the driver and hope that the system has + * been able to recover some MSIX vector resources. + */ + if (!adapter->num_msix_vectors) + return -ENOMEM; + /* disallow open during test */ if (test_bit(__IXGBEVF_TESTING, &adapter->state)) return -EBUSY; @@ -2628,7 +2645,6 @@ static int ixgbevf_open(struct net_device *netdev) err_req_irq: ixgbevf_down(adapter); - ixgbevf_free_irq(adapter); err_setup_rx: ixgbevf_free_all_rx_resources(adapter); err_setup_tx: -- cgit v1.2.3 From 22c12752d183f39aa8e2cc884cfcb23c0cb6d98d Mon Sep 17 00:00:00 2001 From: Lior Levy Date: Tue, 12 Mar 2013 15:49:32 +0000 Subject: igb: fix i350 anti spoofing config Fix a problem in i350 where anti spoofing configuration was written into a wrong register. Signed-off-by: Lior Levy Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 33 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index b64542acfa34..12b1d8480808 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1818,27 +1818,32 @@ out: **/ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf) { - u32 dtxswc; + u32 reg_val, reg_offset; switch (hw->mac.type) { case e1000_82576: + reg_offset = E1000_DTXSWC; + break; case e1000_i350: - dtxswc = rd32(E1000_DTXSWC); - if (enable) { - dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK | - E1000_DTXSWC_VLAN_SPOOF_MASK); - /* The PF can spoof - it has to in order to - * support emulation mode NICs */ - dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); - } else { - dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | - E1000_DTXSWC_VLAN_SPOOF_MASK); - } - wr32(E1000_DTXSWC, dtxswc); + reg_offset = E1000_TXSWC; break; default: - break; + return; + } + + reg_val = rd32(reg_offset); + if (enable) { + reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); + /* The PF can spoof - it has to in order to + * support emulation mode NICs + */ + reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); + } else { + reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); } + wr32(reg_offset, reg_val); } /** -- cgit v1.2.3 From d0f63acc2ff354a525f7bc7ba90e81f49b6c2ef8 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 13 Mar 2013 15:50:24 +0000 Subject: igb: Fix null pointer dereference The max_vfs= option has always been self limiting to the number of VFs supported by the device. fa44f2f1 added SR-IOV configuration via sysfs, but in the process broke this self correction factor. The failing path is: igb_probe igb_sw_init if (max_vfs > 7) { adapter->vfs_allocated_count = 7; ... igb_probe_vfs igb_enable_sriov(, max_vfs) if (num_vfs > 7) { err = -EPERM; ... This leaves vfs_allocated_count = 7 and vf_data = NULL, so we bomb out when igb_probe finally calls igb_reset. It seems like a really bad idea, and somewhat pointless, to set vfs_allocated_count separate from vf_data, but limiting max_vfs is enough to avoid the null pointer. Signed-off-by: Alex Williamson Acked-by: Greg Rose Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 4dbd62968c7a..2ae888678b23 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2652,7 +2652,7 @@ static int igb_sw_init(struct igb_adapter *adapter) if (max_vfs > 7) { dev_warn(&pdev->dev, "Maximum of 7 VFs per PF, using max\n"); - adapter->vfs_allocated_count = 7; + max_vfs = adapter->vfs_allocated_count = 7; } else adapter->vfs_allocated_count = max_vfs; if (adapter->vfs_allocated_count) -- cgit v1.2.3 From d5e51a10d21761faaf069cac6f1c0311cf332820 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 13 Mar 2013 15:50:29 +0000 Subject: igb: SR-IOV init reordering igb is ineffective at setting a lower total VFs because: int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { ... /* Shouldn't change if VFs already enabled */ if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) return -EBUSY; Swap init ordering. Signed-off-by: Alex Williamson Acked-by: Greg Rose Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 2ae888678b23..8496adfc6a68 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2542,8 +2542,8 @@ static void igb_probe_vfs(struct igb_adapter *adapter) if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) return; - igb_enable_sriov(pdev, max_vfs); pci_sriov_set_totalvfs(pdev, 7); + igb_enable_sriov(pdev, max_vfs); #endif /* CONFIG_PCI_IOV */ } -- cgit v1.2.3 From 05ec29e8fa9b6ec8d4ad5d2f6d5fc5467c7970bc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 20 Mar 2013 09:06:29 +0000 Subject: igb: make sensor info static Trivial sparse warning. Signed-off-by: Stephen Hemminger Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 4623502054d5..0478a1abe541 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -39,7 +39,7 @@ #include #ifdef CONFIG_IGB_HWMON -struct i2c_board_info i350_sensor_info = { +static struct i2c_board_info i350_sensor_info = { I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)), }; -- cgit v1.2.3 From 75517d92119a3cd364f618ee962055b3ded8c396 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 20 Mar 2013 09:06:34 +0000 Subject: igb: fix PHC stopping on max freq For 82576 MAC type, max_adj is reported as 1000000000 ppb. However, if this value is passed to igb_ptp_adjfreq_82576, incvalue overflows out of INCVALUE_82576_MASK, resulting in setting of zero TIMINCA.incvalue, stopping the PHC (instead of going at twice the nominal speed). Fix the advertised max_adj value to the largest value hardware can handle. As there is no min_adj value available (-max_adj is used instead), this will also prevent stopping the clock intentionally. It's probably not a big deal, other igb MAC types don't support stopping the clock, either. Signed-off-by: Jiri Benc Acked-by: Matthew Vick Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 0987822359f0..0a237507ee85 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -740,7 +740,7 @@ void igb_ptp_init(struct igb_adapter *adapter) case e1000_82576: snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); adapter->ptp_caps.owner = THIS_MODULE; - adapter->ptp_caps.max_adj = 1000000000; + adapter->ptp_caps.max_adj = 999999881; adapter->ptp_caps.n_ext_ts = 0; adapter->ptp_caps.pps = 0; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; -- cgit v1.2.3 From 751c644b95bb48aaa8825f0c66abbcc184d92051 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 26 Mar 2013 02:27:11 -0700 Subject: pid: Handle the exit of a multi-threaded init. When a multi-threaded init exits and the initial thread is not the last thread to exit the initial thread hangs around as a zombie until the last thread exits. In that case zap_pid_ns_processes needs to wait until there are only 2 hashed pids in the pid namespace not one. v2. Replace thread_pid_vnr(me) == 1 with the test thread_group_leader(me) as suggested by Oleg. Cc: stable@vger.kernel.org Cc: Oleg Nesterov Reported-by: Caj Larsson Signed-off-by: "Eric W. Biederman" --- kernel/pid_namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index c1c3dc1c6023..bea15bdf82b0 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -181,6 +181,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) int nr; int rc; struct task_struct *task, *me = current; + int init_pids = thread_group_leader(me) ? 1 : 2; /* Don't allow any more processes into the pid namespace */ disable_pid_allocation(pid_ns); @@ -230,7 +231,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) */ for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); - if (pid_ns->nr_hashed == 1) + if (pid_ns->nr_hashed == init_pids) break; schedule(); } -- cgit v1.2.3 From 35ccecef6ed48a5602755ddf580c45a026a1dc05 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 25 Mar 2013 14:45:54 -0300 Subject: [media] [REGRESSION] bt8xx: Fix too large height in cropcap Since commit a1fd287780c8e91fed4957b30c757b0c93021162: "[media] bttv-driver: fix two warnings" cropcap.defrect.height and cropcap.bounds.height for the PAL entry are 32 resp 30 pixels too large, if a userspace app (ie xawtv) actually tries to use the full advertised height, the resulting image is broken in ways only a screenshot can describe. The cause of this is the fix for this warning: drivers/media/pci/bt8xx/bttv-driver.c:308:3: warning: initialized field overwritten [-Woverride-init] In this chunk of the commit: @@ -301,11 +301,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* totalwidth */ 1135, /* sqwidth */ 944, /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) /* bt878 (and bt848?) can capture another line below active video. */ - .cropcap.bounds.height = (576 + 2) + 0x20 - 2, + /* sheight */ (576 + 2) + 0x20 - 2, + /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, .name = "NTSC", Which replaces the overriding of cropcap.bounds.height initialization outside of the CROPCAP macro (which also initializes it), with passing a different sheight value to the CROPCAP macro. There are 2 problems with this warning fix: 1) The sheight value is used twice in the CROPCAP macro, and the old code only changed one resulting value. 2) The old code increased the .cropcap.bounds.height value (and did not touch the .cropcap.defrect.height value at all) by 2, where as the fixed code increases it by 32, as the fixed code passes (576 + 2) + 0x20 - 2 to the CROPCAP macro, but the + 0x20 - 2 is already done by the macro so now is done twice for .cropcap.bounds.height, and also is applied to .cropcap.defrect.height where it should not be applied at all. This patch fixes this by adding an extraheight parameter to the CROPCAP entry and using it for the PAL entry. Cc: stable@kernel.org # For Kernel 3.8 Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ccd18e4ee789..54579e4c740b 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -250,17 +250,19 @@ static u8 SRAM_Table[][60] = vdelay start of active video in 2 * field lines relative to trailing edge of /VRESET pulse (VDELAY register). sheight height of active video in 2 * field lines. + extraheight Added to sheight for cropcap.bounds.height only videostart0 ITU-R frame line number of the line corresponding to vdelay in the first field. */ #define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ - vdelay, sheight, videostart0) \ + vdelay, sheight, extraheight, videostart0) \ .cropcap.bounds.left = minhdelayx1, \ /* * 2 because vertically we count field lines times two, */ \ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ /* 4 is a safety margin at the end of the line. */ \ .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ - .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ + .cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) - \ + MIN_VDELAY, \ .cropcap.defrect.left = hdelayx1, \ .cropcap.defrect.top = (videostart0) * 2, \ .cropcap.defrect.width = swidth, \ @@ -301,9 +303,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* totalwidth */ 1135, /* sqwidth */ 944, /* vdelay */ 0x20, - /* bt878 (and bt848?) can capture another - line below active video. */ - /* sheight */ (576 + 2) + 0x20 - 2, + /* sheight */ 576, + /* bt878 (and bt848?) can capture another + line below active video. */ + /* extraheight */ 2, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, @@ -330,6 +333,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_SECAM, @@ -355,6 +359,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x20, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_Nc, @@ -380,6 +385,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_M, @@ -405,6 +411,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_N, @@ -430,6 +437,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x20, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M_JP, @@ -455,6 +463,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x16, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ /* that one hopefully works with the strange timing @@ -484,6 +493,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) } }; -- cgit v1.2.3 From 2f3edfd7e27ad4206acbc2ae99c9df5f46353024 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 26 Mar 2013 16:46:07 +0800 Subject: ARM: imx: fix sync issue between imx_cpu_die and imx_cpu_kill There is a sync issue with hotplug operation. It's possible that when imx_cpu_kill gets running on primary core, the imx_cpu_die execution on the core which is to be killed hasn't been finished yet. The problem will very likely be hit when running suspend without no_console_suspend setting on kernel cmdline. It uses cpu jumping argument register to sync imx_cpu_die and imx_cpu_kill. The register will be set in imx_cpu_die and imx_cpu_kill will wait for the register being cleared to actually kill the cpu. Signed-off-by: Shawn Guo Cc: --- arch/arm/mach-imx/common.h | 2 ++ arch/arm/mach-imx/hotplug.c | 12 ++++++++++++ arch/arm/mach-imx/src.c | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 5a800bfcec5b..5bf4a97ab241 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -110,6 +110,8 @@ void tzic_handle_irq(struct pt_regs *); extern void imx_enable_cpu(int cpu, bool enable); extern void imx_set_cpu_jump(int cpu, void *jump_addr); +extern u32 imx_get_cpu_arg(int cpu); +extern void imx_set_cpu_arg(int cpu, u32 arg); extern void v7_cpu_resume(void); extern u32 *pl310_get_save_ptr(void); #ifdef CONFIG_SMP diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 7bc5fe15dda2..361a253e2b63 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -46,11 +46,23 @@ static inline void cpu_enter_lowpower(void) void imx_cpu_die(unsigned int cpu) { cpu_enter_lowpower(); + /* + * We use the cpu jumping argument register to sync with + * imx_cpu_kill() which is running on cpu0 and waiting for + * the register being cleared to kill the cpu. + */ + imx_set_cpu_arg(cpu, ~0); cpu_do_idle(); } int imx_cpu_kill(unsigned int cpu) { + unsigned long timeout = jiffies + msecs_to_jiffies(50); + + while (imx_get_cpu_arg(cpu) == 0) + if (time_after(jiffies, timeout)) + return 0; imx_enable_cpu(cpu, false); + imx_set_cpu_arg(cpu, 0); return 1; } diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index e15f1555c59b..09a742f8c7ab 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -43,6 +43,18 @@ void imx_set_cpu_jump(int cpu, void *jump_addr) src_base + SRC_GPR1 + cpu * 8); } +u32 imx_get_cpu_arg(int cpu) +{ + cpu = cpu_logical_map(cpu); + return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); +} + +void imx_set_cpu_arg(int cpu, u32 arg) +{ + cpu = cpu_logical_map(cpu); + writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); +} + void imx_src_prepare_restart(void) { u32 val; -- cgit v1.2.3 From 39a352a5b5896403ad4ce842a9bc3845a01c02cd Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 26 Mar 2013 14:35:57 +0100 Subject: NFC: llcp: Keep the connected socket parent pointer alive And avoid decreasing the ack log twice when dequeueing connected LLCP sockets. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/sock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index e488e440186a..8f025746f337 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -270,7 +270,9 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent, } if (sk->sk_state == LLCP_CONNECTED || !newsock) { - nfc_llcp_accept_unlink(sk); + list_del_init(&lsk->accept_queue); + sock_put(sk); + if (newsock) sock_graft(sk, newsock); -- cgit v1.2.3 From aed9913e6fad5a7eccce2b7a3ee6daa96b575157 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 26 Mar 2013 14:47:08 +0800 Subject: ASoC: arizona: remove duplicated include from arizona.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 26e1579c36cb..c979ff2b4191 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 0eaa6cca1f75e12e4f5ec62cbe887330fe3b5fe9 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 26 Mar 2013 14:41:05 +0900 Subject: ASoC: core: Fix to check return value of snd_soc_update_bits_locked() It can be 0 or 1 return value of snd_soc_update_bits_locked() when it is success. So just check return value is negative. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 507d251916af..ff4b45a5d796 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2963,7 +2963,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, val = val << shift; ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); - if (ret != 0) + if (ret < 0) return ret; if (snd_soc_volsw_is_stereo(mc)) { -- cgit v1.2.3 From abe99370b3c583cd0fc4185e7a776b7bb48311c3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Mar 2013 16:58:16 +0100 Subject: ASoC: omap: Call omap_mcbsp_set_threshold() from mcbsp hw_params The omap PCM driver provides a set_threshold callback which gets called by the PCM driver when either playback or capture is started. The only DAI driver which sets this callback is the mcbsp driver. This patch removes the callback from the PCM driver and moves the invocation of the omap_mcbsp_set_threshold() function to the mcbsp hw_params callback since this is the only place where the threshold size can change. Doing so allows us to use the default dmaengine PCM trigger callback in the omap PCM driver. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 12 +++++------- sound/soc/omap/omap-pcm.c | 33 +-------------------------------- sound/soc/omap/omap-pcm.h | 1 - 3 files changed, 6 insertions(+), 40 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 8d2defd6fdbe..406fc8797229 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -62,24 +62,22 @@ enum { * Stream DMA parameters. DMA request line and port address are set runtime * since they are different between OMAP1 and later OMAPs */ -static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) +static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream, + unsigned int packet_size) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_pcm_dma_data *dma_data; int words; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - /* * Configure McBSP threshold based on either: * packet_size, when the sDMA is in packet mode, or based on the * period size in THRESHOLD mode, otherwise use McBSP threshold = 1 * for mono streams. */ - if (dma_data->packet_size) - words = dma_data->packet_size; + if (packet_size) + words = packet_size; else words = 1; @@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } if (mcbsp->pdata->buffer_size) { - dma_data->set_threshold = omap_mcbsp_set_threshold; if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; int divider = 0; @@ -276,6 +273,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, /* Use packet mode for non mono streams */ pkt_size = channels; } + omap_mcbsp_set_threshold(substream, pkt_size); } dma_data->packet_size = pkt_size; diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index c722c2ef9665..1626fb7d2cd2 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -129,37 +129,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct omap_pcm_dma_data *dma_data; - int ret = 0; - - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /* Configure McBSP internal buffer usage */ - if (dma_data->set_threshold) - dma_data->set_threshold(substream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - break; - default: - ret = -EINVAL; - } - - if (ret == 0) - ret = snd_dmaengine_pcm_trigger(substream, cmd); - - return ret; -} - static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream) { snd_pcm_uframes_t offset; @@ -208,7 +177,7 @@ static struct snd_pcm_ops omap_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = omap_pcm_hw_params, .hw_free = omap_pcm_hw_free, - .trigger = omap_pcm_trigger, + .trigger = snd_dmaengine_pcm_trigger, .pointer = omap_pcm_pointer, .mmap = omap_pcm_mmap, }; diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index cabe74c4068b..39e6e4556b82 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -31,7 +31,6 @@ struct omap_pcm_dma_data { char *name; /* stream identifier */ int dma_req; /* DMA request line */ unsigned long port_addr; /* transmit/receive register */ - void (*set_threshold)(struct snd_pcm_substream *substream); int data_type; /* 8, 16, 32 (bits) or 0 to let omap-pcm * to decide the sDMA data type */ int packet_size; /* packet size only in PACKET mode */ -- cgit v1.2.3 From 36300fd09823be8f7d6feaaa79ddbf54cf205378 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghiu Date: Mon, 25 Mar 2013 16:33:59 +0200 Subject: ASoC: core: Use PTR_RET function Used PTR_RET function instead of IS_ERR and PTR_ERR. Patch found using coccinelle. Signed-off-by: Alexandru Gheorghiu Signed-off-by: Mark Brown --- sound/soc/soc-io.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 29183ef2b93d..8ca9ecc5ac57 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -158,10 +158,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, return -EINVAL; } - if (IS_ERR(codec->control_data)) - return PTR_ERR(codec->control_data); - - return 0; + return PTR_RET(codec->control_data); } EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); #else -- cgit v1.2.3 From cb20d5757bbe79d9c9e4210e232934792be2336e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:01 +0100 Subject: ASoC: ux500_pcm: Remove duplicated SNDRV_PCM_HW_PARAM_PERIODS constraint The generic dmaengine based PCM driver code takes care of setting this constraint, there is no need of doing it manually in the ux500 driver. Signed-off-by: Lars-Peter Clausen Acked-by: Ola Lilja Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_pcm.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 846fa82a58d0..375ca6ba3ebb 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -111,15 +111,6 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw_capture); - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) { - dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n", - __func__, ret); - return ret; - } - dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__, snd_pcm_stream_str(substream)); runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? -- cgit v1.2.3 From 023934b4052b1a955ac8d68c8d4b216d1c55c611 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:02 +0100 Subject: ASoC: spear_pcm: No need to wrap snd_dmaengine_pcm_close() If a PCM driver using the dmaengine PCM helper functions doesn't need to do anything special in its pcm_close callback, snd_dmaengine_pcm_close can be used directly for as the pcm_close callback and there is no need to wrap it in a custom function. Signed-off-by: Lars-Peter Clausen Acked-by: Rajeev Kumar Signed-off-by: Mark Brown --- sound/soc/spear/spear_pcm.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 9b76cc5a1148..32431d619174 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -73,14 +73,6 @@ static int spear_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int spear_pcm_close(struct snd_pcm_substream *substream) -{ - - snd_dmaengine_pcm_close(substream); - - return 0; -} - static int spear_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -93,7 +85,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops spear_pcm_ops = { .open = spear_pcm_open, - .close = spear_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = spear_pcm_hw_params, .hw_free = spear_pcm_hw_free, -- cgit v1.2.3 From 340af748bc4004982a1a11ea2d81a4bffe6eb975 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:03 +0100 Subject: ASoC: omap-pcm: No need to wrap snd_dmaengine_pcm_close() If a PCM driver using the dmaengine PCM helper functions doesn't need to do anything special in its pcm_close callback, snd_dmaengine_pcm_close can be used directly for as the pcm_close callback and there is no need to wrap it in a custom function. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-pcm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 1626fb7d2cd2..6c842c7ef9e6 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -154,12 +154,6 @@ static int omap_pcm_open(struct snd_pcm_substream *substream) &dma_data->dma_req); } -static int omap_pcm_close(struct snd_pcm_substream *substream) -{ - snd_dmaengine_pcm_close(substream); - return 0; -} - static int omap_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -173,7 +167,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops omap_pcm_ops = { .open = omap_pcm_open, - .close = omap_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = omap_pcm_hw_params, .hw_free = omap_pcm_hw_free, -- cgit v1.2.3 From 3021bd38ed31380df5e270451162feca83aef40f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:04 +0100 Subject: ASoC: tegra_pcm: No need to wrap snd_dmaengine_pcm_close() If a PCM driver using the dmaengine PCM helper functions doesn't need to do anything special in its pcm_close callback, snd_dmaengine_pcm_close can be used directly for as the pcm_close callback and there is no need to wrap it in a custom function. Signed-off-by: Lars-Peter Clausen Acked-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_pcm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index c925ab0adeb6..e67af0b5d35d 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -75,12 +75,6 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int tegra_pcm_close(struct snd_pcm_substream *substream) -{ - snd_dmaengine_pcm_close(substream); - return 0; -} - static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -160,7 +154,7 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops tegra_pcm_ops = { .open = tegra_pcm_open, - .close = tegra_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = tegra_pcm_hw_params, .hw_free = tegra_pcm_hw_free, -- cgit v1.2.3 From 8c4e56fd5595105128077c2bbdfde3c15a4c2d91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:05 +0100 Subject: ASoC: ux500_pcm: No need to wrap snd_dmaengine_pcm_close() If a PCM driver using the dmaengine PCM helper functions doesn't need to do anything special in its pcm_close callback, snd_dmaengine_pcm_close can be used directly for as the pcm_close callback and there is no need to wrap it in a custom function. Signed-off-by: Lars-Peter Clausen Acked-by: Ola Lilja Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_pcm.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 375ca6ba3ebb..d000ba271cab 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -160,18 +160,6 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int ux500_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *dai = rtd->cpu_dai; - - dev_dbg(dai->dev, "%s: Enter\n", __func__); - - snd_dmaengine_pcm_close(substream); - - return 0; -} - static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -246,7 +234,7 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops ux500_pcm_ops = { .open = ux500_pcm_open, - .close = ux500_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = ux500_pcm_hw_params, .hw_free = ux500_pcm_hw_free, -- cgit v1.2.3 From a85fc1b073406b3848661fcbb452497930dcc8af Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:06 +0100 Subject: ASoC: atmel-pcm-dma: No need to wrap snd_dmaengine_pcm_close() If a PCM driver using the dmaengine PCM helper functions doesn't need to do anything special in its pcm_close callback, snd_dmaengine_pcm_close can be used directly for as the pcm_close callback and there is no need to wrap it in a custom function. Signed-off-by: Lars-Peter Clausen Tested-by: Bo Shen Acked-by: Bo Shen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm-dma.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index 30184a4a147a..396bf78c7a2d 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -199,16 +199,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - snd_dmaengine_pcm_close(substream); - - return 0; -} - static struct snd_pcm_ops atmel_pcm_ops = { .open = atmel_pcm_open, - .close = atmel_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, .prepare = atmel_pcm_dma_prepare, -- cgit v1.2.3 From ebd59b07ecd9d35d5bc88c91a4878fbb4549ed42 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:07 +0100 Subject: ASoC: ux500_pcm: No need to use snd_dmaengine_pcm_set_data() The driver never uses snd_dmaengine_pcm_get_data(), so there is no need to use snd_dmaengine_pcm_set_data(). Signed-off-by: Lars-Peter Clausen Acked-by: Ola Lilja Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_pcm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index d000ba271cab..1ab36fa845cd 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -155,8 +155,6 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) return ret; } - snd_dmaengine_pcm_set_data(substream, dma_cfg); - return 0; } -- cgit v1.2.3 From 593b66fbbcac78b73ec17270c874f6db8eabd97c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:08 +0100 Subject: ASoC: speaer_pcm: No need to use snd_dmaengine_pcm_set_data() The driver never uses snd_dmaengine_pcm_get_data(), so there is no need to use snd_dmaengine_pcm_set_data(). Signed-off-by: Lars-Peter Clausen Acked-by: Rajeev Kumar Signed-off-by: Mark Brown --- sound/soc/spear/spear_pcm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 32431d619174..db75d72c4805 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -64,13 +64,7 @@ static int spear_pcm_open(struct snd_pcm_substream *substream) if (ret) return ret; - ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data); - if (ret) - return ret; - - snd_dmaengine_pcm_set_data(substream, dma_data); - - return 0; + return snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data) } static int spear_pcm_mmap(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 5fe668a1d2c27223fea4991ebf90ee28b7d1941c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:09 +0100 Subject: ASoC: atmel-pcm-dma: Do not use snd_dmaengine_pcm_{set,get}_data() We want to get rid of snd_dmaengine_pcm_{set,get}_data(). All instances of snd_dmaengine_pcm_get_data() in the atmel pcm driver can easily be replaced with snd_soc_dai_get_dma_data(). Signed-off-by: Lars-Peter Clausen Tested-by: Bo Shen Acked-by: Bo Shen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm-dma.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index 396bf78c7a2d..b8570e3e1b57 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { static void atmel_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; - prtd = snd_dmaengine_pcm_get_data(substream); + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (ssc_sr & prtd->mask->ssc_error) { if (snd_pcm_running(substream)) @@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave) } static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd) { - struct atmel_pcm_dma_params *prtd; struct ssc_device *ssc; struct dma_chan *dma_chan; struct dma_slave_config slave_config; int ret; - prtd = snd_dmaengine_pcm_get_data(substream); ssc = prtd->ssc; ret = snd_hwparams_to_dma_slave_config(substream, params, @@ -164,9 +163,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_dmaengine_pcm_set_data(substream, prtd); - - ret = atmel_pcm_configure_dma(substream, params); + ret = atmel_pcm_configure_dma(substream, params, prtd); if (ret) { pr_err("atmel-pcm: failed to configure dmai\n"); goto err; @@ -182,9 +179,10 @@ err: static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; - prtd = snd_dmaengine_pcm_get_data(substream); + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); -- cgit v1.2.3 From 453807f3006757a5661c4000262d7d9284b5214c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:10 +0100 Subject: ASoC: ep93xx: Use ep93xx_dma_params instead of ep93xx_pcm_dma_params Currently the ep93xx_dma_params struct which is passed to the dmaengine driver is constructed at runtime from the ep93xx_pcm_dma_params that gets passed to the ep93xx PCM driver from one of the ep93xx DAI drivers. The ep93xx_pcm_dma_params struct is almost identical to the ep93xx_dma_params struct. The only missing field is the 'direction' field, which is computed at runtime in the PCM driver based on the current substream. Since we know in advance which ep93xx_pcm_dma_params struct is being used for which substream at compile time, we also already know which direction to use at compile time. So we can easily replace all instances of ep93xx_pcm_dma_params with their ep93xx_dma_params counterpart. This allows us to simplify the code in the ep93xx pcm driver quite a bit. Signed-off-by: Lars-Peter Clausen Reviewed-by: Ryan Mallon Signed-off-by: Mark Brown --- sound/soc/cirrus/edb93xx.c | 1 - sound/soc/cirrus/ep93xx-ac97.c | 9 +++++---- sound/soc/cirrus/ep93xx-i2s.c | 12 ++++++------ sound/soc/cirrus/ep93xx-pcm.c | 37 +++---------------------------------- sound/soc/cirrus/ep93xx-pcm.h | 20 -------------------- sound/soc/cirrus/simone.c | 2 -- sound/soc/cirrus/snappercl15.c | 1 - 7 files changed, 14 insertions(+), 68 deletions(-) delete mode 100644 sound/soc/cirrus/ep93xx-pcm.h diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 5db68cf7b281..c43fb214558a 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -27,7 +27,6 @@ #include #include #include -#include "ep93xx-pcm.h" static int edb93xx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 1738d28fb04f..8d3088647e44 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -23,7 +23,6 @@ #include #include -#include "ep93xx-pcm.h" /* * Per channel (1-4) registers. @@ -101,14 +100,16 @@ struct ep93xx_ac97_info { /* currently ALSA only supports a single AC97 device */ static struct ep93xx_ac97_info *ep93xx_ac97_info; -static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { +static struct ep93xx_dma_data ep93xx_ac97_pcm_out = { .name = "ac97-pcm-out", .dma_port = EP93XX_DMA_AAC1, + .direction = DMA_MEM_TO_DEV, }; -static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { +static struct ep93xx_dma_data ep93xx_ac97_pcm_in = { .name = "ac97-pcm-in", .dma_port = EP93XX_DMA_AAC1, + .direction = DMA_DEV_TO_MEM, }; static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info, @@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream, static int ep93xx_ac97_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct ep93xx_pcm_dma_params *dma_data; + struct ep93xx_dma_data *dma_data; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dma_data = &ep93xx_ac97_pcm_out; diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 323ed69b7975..aa124f86f60e 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -30,8 +30,6 @@ #include #include -#include "ep93xx-pcm.h" - #define EP93XX_I2S_TXCLKCFG 0x00 #define EP93XX_I2S_RXCLKCFG 0x04 #define EP93XX_I2S_GLCTRL 0x0C @@ -62,18 +60,20 @@ struct ep93xx_i2s_info { struct clk *mclk; struct clk *sclk; struct clk *lrclk; - struct ep93xx_pcm_dma_params *dma_params; + struct ep93xx_dma_data *dma_data; void __iomem *regs; }; -struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { +struct ep93xx_dma_data ep93xx_i2s_dma_data[] = { [SNDRV_PCM_STREAM_PLAYBACK] = { .name = "i2s-pcm-out", .dma_port = EP93XX_DMA_I2S1, + .direction = DMA_MEM_TO_DEV, }, [SNDRV_PCM_STREAM_CAPTURE] = { .name = "i2s-pcm-in", .dma_port = EP93XX_DMA_I2S1, + .direction = DMA_DEV_TO_MEM, }, }; @@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; snd_soc_dai_set_dma_data(cpu_dai, substream, - &info->dma_params[substream->stream]); + &info->dma_data[substream->stream]); return 0; } @@ -403,7 +403,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, info); - info->dma_params = ep93xx_i2s_dma_params; + info->dma_data = ep93xx_i2s_dma_data; err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai); if (err) diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 72eb7a49e16a..298946f790eb 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@ -29,8 +29,6 @@ #include #include -#include "ep93xx-pcm.h" - static const struct snd_pcm_hardware ep93xx_pcm_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -68,40 +66,11 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) static int ep93xx_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct ep93xx_pcm_dma_params *dma_params; - struct ep93xx_dma_data *dma_data; - int ret; snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); - dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL); - if (!dma_data) - return -ENOMEM; - - dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); - dma_data->port = dma_params->dma_port; - dma_data->name = dma_params->name; - dma_data->direction = snd_pcm_substream_to_dma_direction(substream); - - ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data); - if (ret) { - kfree(dma_data); - return ret; - } - - snd_dmaengine_pcm_set_data(substream, dma_data); - - return 0; -} - -static int ep93xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); - - snd_dmaengine_pcm_close(substream); - kfree(dma_data); - return 0; + return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, + snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); } static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, @@ -131,7 +100,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops ep93xx_pcm_ops = { .open = ep93xx_pcm_open, - .close = ep93xx_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = ep93xx_pcm_hw_params, .hw_free = ep93xx_pcm_hw_free, diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h deleted file mode 100644 index 111e1121ecb8..000000000000 --- a/sound/soc/cirrus/ep93xx-pcm.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface - * - * Copyright (C) 2006 Lennert Buytenhek - * Copyright (C) 2006 Applied Data Systems - * - * 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. - */ - -#ifndef _EP93XX_SND_SOC_PCM_H -#define _EP93XX_SND_SOC_PCM_H - -struct ep93xx_pcm_dma_params { - char *name; - int dma_port; -}; - -#endif /* _EP93XX_SND_SOC_PCM_H */ diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c index a397bb0d8179..4d094d00c34a 100644 --- a/sound/soc/cirrus/simone.c +++ b/sound/soc/cirrus/simone.c @@ -21,8 +21,6 @@ #include #include -#include "ep93xx-pcm.h" - static struct snd_soc_dai_link simone_dai = { .name = "AC97", .stream_name = "AC97 HiFi", diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c index 9d77fe28dfcc..69041074f2c1 100644 --- a/sound/soc/cirrus/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c @@ -21,7 +21,6 @@ #include #include "../codecs/tlv320aic23.h" -#include "ep93xx-pcm.h" #define CODEC_CLOCK 5644800 -- cgit v1.2.3 From ac581e60dfb4cc55ac20cca18202c7689d324aa7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:11 +0100 Subject: ASoC: mmp-pcm: Allocate dma filter parameters on the stack The dma filter parameters are only used within filter callback, so there is no need to allocate them on the heap and keep them around until the PCM has been closed. Signed-off-by: Lars-Peter Clausen Tested-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 190eb0bccf5f..6c3980252bf6 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -118,9 +118,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct platform_device *pdev = to_platform_device(rtd->platform->dev); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct mmp_dma_data *dma_data; + struct mmp_dma_data dma_data; struct resource *r; - int ret; r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream); if (!r) @@ -128,33 +127,11 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &mmp_pcm_hardware[substream->stream]); - dma_data = devm_kzalloc(&pdev->dev, - sizeof(struct mmp_dma_data), GFP_KERNEL); - if (dma_data == NULL) - return -ENOMEM; - dma_data->dma_res = r; - dma_data->ssp_id = cpu_dai->id; + dma_data.dma_res = r; + dma_data.ssp_id = cpu_dai->id; - ret = snd_dmaengine_pcm_open(substream, filter, dma_data); - if (ret) { - devm_kfree(&pdev->dev, dma_data); - return ret; - } - - snd_dmaengine_pcm_set_data(substream, dma_data); - return 0; -} - -static int mmp_pcm_close(struct snd_pcm_substream *substream) -{ - struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct platform_device *pdev = to_platform_device(rtd->platform->dev); - - snd_dmaengine_pcm_close(substream); - devm_kfree(&pdev->dev, dma_data); - return 0; + return snd_dmaengine_pcm_open(substream, filter, &dma_data); } static int mmp_pcm_mmap(struct snd_pcm_substream *substream, @@ -171,7 +148,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream, struct snd_pcm_ops mmp_pcm_ops = { .open = mmp_pcm_open, - .close = mmp_pcm_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = mmp_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, -- cgit v1.2.3 From 312bb4f626328fdc246c8d13082ab00e26e7d048 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:12 +0100 Subject: ASoC: imx-pcm: Embed the imx_dma_data struct in the dma_params struct Currently the imx_dma_data struct, which gets passed to the dmaengine driver, is allocated and constructed in the pcm driver from the data stored in the dma_params struct. The dma_params struct gets passed to the pcm driver from the dai driver. Instead of going this route of indirection embed the dma_data struct directly into the dma_params struct and let the dai driver fill it in. This allows us to simplify the imx-pcm-dma driver quite a bit, since it doesn't have care about memory managing the imx_dma_data struct anymore. Signed-off-by: Lars-Peter Clausen Tested-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 17 +++++++++-------- sound/soc/fsl/imx-pcm-dma.c | 35 ++--------------------------------- sound/soc/fsl/imx-pcm.h | 17 +++++++++++++++-- sound/soc/fsl/imx-ssi.c | 12 ++++++++---- 4 files changed, 34 insertions(+), 47 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7decbd9b2340..2cce1ce1b7dd 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -649,6 +649,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) const uint32_t *iprop; struct resource res; char name[64]; + bool shared; /* SSIs that are not connected on the board should have a * status = "disabled" @@ -755,14 +756,14 @@ static int fsl_ssi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "could not get dma events\n"); goto error_clk; } - ssi_private->dma_params_tx.dma = dma_events[0]; - ssi_private->dma_params_rx.dma = dma_events[1]; - - ssi_private->dma_params_tx.shared_peripheral = - of_device_is_compatible(of_get_parent(np), - "fsl,spba-bus"); - ssi_private->dma_params_rx.shared_peripheral = - ssi_private->dma_params_tx.shared_peripheral; + + shared = of_device_is_compatible(of_get_parent(np), + "fsl,spba-bus"); + + imx_pcm_dma_params_init_data(&ssi_private->dma_params_tx, + dma_events[0], shared); + imx_pcm_dma_params_init_data(&ssi_private->dma_params_rx, + dma_events[1], shared); } /* Initialize the the device_attribute structure */ diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 500f8ce55d78..6832c498457a 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -30,8 +30,6 @@ #include #include -#include - #include "imx-pcm.h" static bool filter(struct dma_chan *chan, void *param) @@ -101,46 +99,17 @@ static int snd_imx_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; - struct imx_dma_data *dma_data; - int ret; snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL); - if (!dma_data) - return -ENOMEM; - - dma_data->peripheral_type = dma_params->shared_peripheral ? - IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI; - dma_data->priority = DMA_PRIO_HIGH; - dma_data->dma_request = dma_params->dma; - - ret = snd_dmaengine_pcm_open(substream, filter, dma_data); - if (ret) { - kfree(dma_data); - return ret; - } - - snd_dmaengine_pcm_set_data(substream, dma_data); - - return 0; -} - -static int snd_imx_close(struct snd_pcm_substream *substream) -{ - struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); - - snd_dmaengine_pcm_close(substream); - kfree(dma_data); - - return 0; + return snd_dmaengine_pcm_open(substream, filter, &dma_params->dma_data); } static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, - .close = snd_imx_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 5ae13a13a353..16eaf5a09f53 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -13,18 +13,31 @@ #ifndef _IMX_PCM_H #define _IMX_PCM_H +#include + /* * Do not change this as the FIQ handler depends on this size */ #define IMX_SSI_DMABUF_SIZE (64 * 1024) struct imx_pcm_dma_params { - int dma; unsigned long dma_addr; int burstsize; - bool shared_peripheral; /* The peripheral is on SPBA bus */ + struct imx_dma_data dma_data; }; +static inline void +imx_pcm_dma_params_init_data(struct imx_pcm_dma_params *params, + int dma, bool shared) +{ + params->dma_data.dma_request = dma; + params->dma_data.priority = DMA_PRIO_HIGH; + if (shared) + params->dma_data.peripheral_type = IMX_DMATYPE_SSI_SP; + else + params->dma_data.peripheral_type = IMX_DMATYPE_SSI; +} + int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 55464a5b0706..14018c4628ec 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -577,12 +577,16 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->dma_params_rx.burstsize = 4; res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); - if (res) - ssi->dma_params_tx.dma = res->start; + if (res) { + imx_pcm_dma_params_init_data(&ssi->dma_params_tx, res->start, + false); + } res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); - if (res) - ssi->dma_params_rx.dma = res->start; + if (res) { + imx_pcm_dma_params_init_data(&ssi->dma_params_rx, res->start, + false); + } platform_set_drvdata(pdev, ssi); -- cgit v1.2.3 From b7e5e91210fc9d40f93f87e386823e4ba9b32805 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:13 +0100 Subject: ASoC: mxs: Embed the mxs_dma_data struct in the mxs_pcm_dma_params struct Currently the mxs_dma_data struct, which gets passed to the dmaengine driver, is allocated in the pcm driver's open callback. The mxs_dma_data struct has exactly one field which is initialized from the the same field in the mxs_pcm_dma_params struct. The mxs_pcm_dma_params struct gets passed to the pcm driver from the dai driver. Instead of taking this indirection embed the mxs_dma_data struct directly in the mxs_pcm_dma_params struct. This allows us to simplify the pcm driver quite a bit, since we don't have to care about memory managing the mxs_dma_data struct anymore. Signed-off-by: Lars-Peter Clausen Tested-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-pcm.c | 43 +++++-------------------------------------- sound/soc/mxs/mxs-pcm.h | 4 +++- sound/soc/mxs/mxs-saif.c | 6 +++--- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index 564b5b60319d..ebbef8597554 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -39,11 +38,6 @@ #include "mxs-pcm.h" -struct mxs_pcm_dma_data { - struct mxs_dma_data dma_data; - struct mxs_pcm_dma_params *dma_params; -}; - static struct snd_pcm_hardware snd_mxs_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -66,8 +60,7 @@ static struct snd_pcm_hardware snd_mxs_hardware = { static bool filter(struct dma_chan *chan, void *param) { - struct mxs_pcm_dma_data *pcm_dma_data = param; - struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params; + struct mxs_pcm_dma_params *dma_params = param; if (!mxs_dma_is_apbx(chan)) return false; @@ -75,7 +68,7 @@ static bool filter(struct dma_chan *chan, void *param) if (chan->chan_id != dma_params->chan_num) return false; - chan->private = &pcm_dma_data->dma_data; + chan->private = &dma_params->dma_data; return true; } @@ -91,37 +84,11 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, static int snd_mxs_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mxs_pcm_dma_data *pcm_dma_data; - int ret; - - pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL); - if (pcm_dma_data == NULL) - return -ENOMEM; - - pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq; - - ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data); - if (ret) { - kfree(pcm_dma_data); - return ret; - } snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); - snd_dmaengine_pcm_set_data(substream, pcm_dma_data); - - return 0; -} - -static int snd_mxs_close(struct snd_pcm_substream *substream) -{ - struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream); - - snd_dmaengine_pcm_close(substream); - kfree(pcm_dma_data); - - return 0; + return snd_dmaengine_pcm_open(substream, filter, + snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); } static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, @@ -137,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops mxs_pcm_ops = { .open = snd_mxs_open, - .close = snd_mxs_close, + .close = snd_dmaengine_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_mxs_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h index 35ba2ca42384..3aa918f9ed3e 100644 --- a/sound/soc/mxs/mxs-pcm.h +++ b/sound/soc/mxs/mxs-pcm.h @@ -19,8 +19,10 @@ #ifndef _MXS_PCM_H #define _MXS_PCM_H +#include + struct mxs_pcm_dma_params { - int chan_irq; + struct mxs_dma_data dma_data; int chan_num; }; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 3a2aa1d19b93..f13bd8730b0f 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -753,9 +753,9 @@ static int mxs_saif_probe(struct platform_device *pdev) return ret; } - saif->dma_param.chan_irq = platform_get_irq(pdev, 1); - if (saif->dma_param.chan_irq < 0) { - ret = saif->dma_param.chan_irq; + saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1); + if (saif->dma_param.dma_data.chan_irq < 0) { + ret = saif->dma_param.dma_data.chan_irq; dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", ret); return ret; -- cgit v1.2.3 From b1bd7f62cf2b854316a9a8b2442a8014dbe29a47 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:14 +0100 Subject: ASoC: dmaengine-pcm: Remove snd_dmaengine_pcm_{set,get}_data These functions were initially added to be able to support some oddball dma drivers, but all users have been updated to deal with the situation without the help of snd_dmaengine_pcm_{set,get}_data, so these two functions can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 3 --- sound/soc/soc-dmaengine-pcm.c | 29 ----------------------------- 2 files changed, 32 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index b877334bbb0f..f8a70312adb8 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -32,9 +32,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream) return DMA_DEV_TO_MEM; } -void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data); -void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream); - int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd); diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 111b7d921e89..e8b1215b8c1b 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data { dma_cookie_t cookie; unsigned int pos; - - void *data; }; static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( @@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( return substream->runtime->private_data; } -/** - * snd_dmaengine_pcm_set_data - Set dmaengine substream private data - * @substream: PCM substream - * @data: Data to set - */ -void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data) -{ - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - - prtd->data = data; -} -EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data); - -/** - * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data - * @substream: PCM substream - * - * Returns the data previously set with snd_dmaengine_pcm_set_data - */ -void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream) -{ - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - - return prtd->data; -} -EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data); - struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); -- cgit v1.2.3 From 03409071ce2751ca124f35edebe4bcad52de22c2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 12 Feb 2013 13:00:31 +0000 Subject: extcon: arizona: Factor out magic application We have a very similar sequence doing magic writes in several places (one of which missed an update to interlock with the CODEC driver) so factor it out into a function. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 91 ++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index dc357a4051f6..896a923546e0 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -100,6 +100,39 @@ static const char *arizona_cable[] = { NULL, }; +static void arizona_extcon_do_magic(struct arizona_extcon_info *info, + unsigned int magic) +{ + struct arizona *arizona = info->arizona; + unsigned int val; + int ret; + + mutex_lock(&arizona->dapm->card->dapm_mutex); + + ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read output enables: %d\n", + ret); + val = 0; + } + + if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { + ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + + ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + } + + mutex_unlock(&arizona->dapm->card->dapm_mutex); +} + static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) { struct arizona *arizona = info->arizona; @@ -484,7 +517,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; int report = ARIZONA_CABLE_HEADPHONE; - unsigned int val; int ret, reading; mutex_lock(&info->lock); @@ -539,28 +571,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) dev_err(arizona->dev, "Failed to report HP/line: %d\n", ret); - mutex_lock(&arizona->dapm->card->dapm_mutex); - - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; - } - - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", - ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0); - if (ret != 0) - dev_warn(arizona->dev, "Failed to undo magic: %d\n", - ret); - } - - mutex_unlock(&arizona->dapm->card->dapm_mutex); + arizona_extcon_do_magic(info, 0); done: if (id_gpio) @@ -606,13 +617,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) if (info->mic) arizona_stop_mic(info); - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); + arizona_extcon_do_magic(info, 0x4000); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, @@ -653,7 +658,6 @@ err: static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) { struct arizona *arizona = info->arizona; - unsigned int val; int ret; dev_dbg(arizona->dev, "Starting identification via HPDET\n"); @@ -665,30 +669,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) arizona_extcon_pulse_micbias(info); - mutex_lock(&arizona->dapm->card->dapm_mutex); - - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; - } - - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, - 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", - ret); - - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, - 0x4000); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", - ret); - } - - mutex_unlock(&arizona->dapm->card->dapm_mutex); + arizona_extcon_do_magic(info, 0x4000); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, -- cgit v1.2.3 From 4fdc782416b29b77681ceec9ba74cdf5ee5e4051 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 11 Mar 2013 22:21:28 +0800 Subject: x86, io_apic: remove duplicated include from irq_remapping.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: Joerg Roedel --- drivers/iommu/irq_remapping.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index d56f8c17c5fe..7c11ff368d07 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From f607e31ce3963327f749b56c65dfec2642aa623c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Feb 2013 18:36:53 +0000 Subject: ASoC: arizona: Fix interaction between headphone outputs and identification Running HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running. Do the ASoC side of this by storing the enable state in the core driver structure and only writing to the device if a flag indicating that the accessory detection side is in a state where it can have the headphone output stage enabled. Signed-off-by: Mark Brown --- include/linux/mfd/arizona/core.h | 3 +++ sound/soc/codecs/arizona.c | 33 +++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 3 +++ sound/soc/codecs/wm5102.c | 8 ++++---- sound/soc/codecs/wm5110.c | 8 ++++---- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index a710255528d7..cc281368dc55 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -100,6 +100,9 @@ struct arizona { struct regmap_irq_chip_data *aod_irq_chip; struct regmap_irq_chip_data *irq_chip; + bool hpdet_magic; + unsigned int hp_ena; + struct mutex clk_lock; int clk32k_ref; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ac948a671ea6..e7d34711412c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -364,6 +364,39 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(arizona_out_ev); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec); + unsigned int mask = 1 << w->shift; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = mask; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 0; + break; + default: + return -EINVAL; + } + + /* Store the desired state for the HP outputs */ + priv->arizona->hp_ena &= ~mask; + priv->arizona->hp_ena |= val; + + /* Force off if HPDET magic is active */ + if (priv->arizona->hpdet_magic) + val = 0; + + snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val); + + return arizona_out_ev(w, kcontrol, event); +} +EXPORT_SYMBOL_GPL(arizona_hp_ev); + static unsigned int arizona_sysclk_48k_rates[] = { 6144000, 12288000, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 116372c91f5d..13dd2916b721 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -184,6 +184,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w, extern int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b82bbf584146..2657aad3f8b1 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1131,11 +1131,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"), SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index cdeb301da1f6..7841b42a819c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -551,11 +551,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, -- cgit v1.2.3 From df8c3dbee9e6f19ddb0ae8e05cdf76eb2d3b7f00 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 22 Feb 2013 18:38:03 +0000 Subject: extcon: arizona: Fix interaction between headphone outputs and identification Running HPDET while the headphone outputs are enabled can disrupt the operation of HPDET. In order to avoid this HPDET needs to disable the headphone outputs and ASoC needs to not enable them while HPDET is running. For extcon instead of checking if the headphone output is enabled when doing magic application unconditionally disable the output and restore the state which ASoC wants set when undoing the magic. Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 896a923546e0..b28927972128 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -104,29 +104,45 @@ static void arizona_extcon_do_magic(struct arizona_extcon_info *info, unsigned int magic) { struct arizona *arizona = info->arizona; - unsigned int val; int ret; mutex_lock(&arizona->dapm->card->dapm_mutex); - ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read output enables: %d\n", - ret); - val = 0; - } + arizona->hpdet_magic = magic; - if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, - magic); + /* Keep the HP output stages disabled while doing the magic */ + if (magic) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT1L_ENA | + ARIZONA_OUT1R_ENA, 0); if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + dev_warn(arizona->dev, + "Failed to disable headphone outputs: %d\n", + ret); + } + + ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, - magic); + ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, + magic); + if (ret != 0) + dev_warn(arizona->dev, "Failed to do magic: %d\n", + ret); + + /* Restore the desired state while not doing the magic */ + if (!magic) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_OUTPUT_ENABLES_1, + ARIZONA_OUT1L_ENA | + ARIZONA_OUT1R_ENA, arizona->hp_ena); if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + dev_warn(arizona->dev, + "Failed to restore headphone outputs: %d\n", ret); } -- cgit v1.2.3 From 76a0e68129d7d24eb995a6871ab47081bbfa0acc Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Mon, 25 Mar 2013 22:26:21 +0000 Subject: pch_gbe: fix ip_summed checksum reporting on rx skb->ip_summed should be CHECKSUM_UNNECESSARY when the driver reports that checksums were correct and CHECKSUM_NONE in any other case. They're currently placed vice versa, which breaks the forwarding scenario. Fix it by placing them as described above. Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 39ab4d09faaa..73ce7dd6b954 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1726,9 +1726,9 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) - skb->ip_summed = CHECKSUM_NONE; - else skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; napi_gro_receive(&adapter->napi, skb); (*work_done)++; -- cgit v1.2.3 From eba0e3c3a0ba7b96f01cbe997680f6a4401a0bfc Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 26 Mar 2013 10:49:55 +0800 Subject: USB: serial: fix hang when opening port Johan's 'fix use-after-free in TIOCMIWAIT' patchset[1] introduces one bug which can cause kernel hang when opening port. This patch initialized the 'port->delta_msr_wait' waitqueue head to fix the bug which is introduced in 3.9-rc4. [1], http://marc.info/?l=linux-usb&m=136368139627876&w=2 Cc: stable Signed-off-by: Ming Lei Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2e70efa08b77..5d9b178484fd 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -903,6 +903,7 @@ static int usb_serial_probe(struct usb_interface *interface, port->port.ops = &serial_port_ops; port->serial = serial; spin_lock_init(&port->lock); + init_waitqueue_head(&port->delta_msr_wait); /* Keep this for private driver use for the moment but should probably go away */ INIT_WORK(&port->work, usb_serial_port_work); -- cgit v1.2.3 From 14134f6584212d585b310ce95428014b653dfaf6 Mon Sep 17 00:00:00 2001 From: dingtianhong Date: Mon, 25 Mar 2013 17:02:04 +0000 Subject: af_unix: dont send SCM_CREDENTIAL when dest socket is NULL SCM_SCREDENTIALS should apply to write() syscalls only either source or destination socket asserted SOCK_PASSCRED. The original implememtation in maybe_add_creds is wrong, and breaks several LSB testcases ( i.e. /tset/LSB.os/netowkr/recvfrom/T.recvfrom). Origionally-authored-by: Karel Srot Signed-off-by: Ding Tianhong Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/unix/af_unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f153a8d6e339..971282b6f6a3 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1412,8 +1412,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, if (UNIXCB(skb).cred) return; if (test_bit(SOCK_PASSCRED, &sock->flags) || - !other->sk_socket || - test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) { + (other->sk_socket && + test_bit(SOCK_PASSCRED, &other->sk_socket->flags))) { UNIXCB(skb).pid = get_pid(task_tgid(current)); UNIXCB(skb).cred = get_current_cred(); } -- cgit v1.2.3 From 9fe16b78ee17579cb4f333534cf7043e94c67024 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 26 Mar 2013 17:43:28 +0100 Subject: bonding: remove already created master sysfs link on failure If slave sysfs symlink failes to be created - we end up without removing the master sysfs symlink. Remove it in case of failure. Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_sysfs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1c9e09fbdff8..db103e03ba05 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -183,6 +183,11 @@ int bond_create_slave_symlinks(struct net_device *master, sprintf(linkname, "slave_%s", slave->name); ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); + + /* free the master link created earlier in case of error */ + if (ret) + sysfs_remove_link(&(slave->dev.kobj), "master"); + return ret; } -- cgit v1.2.3 From 4adaa611020fa6ac65b0ac8db78276af4ec04e63 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 26 Mar 2013 13:07:00 -0400 Subject: Btrfs: fix race between mmap writes and compression Btrfs uses page_mkwrite to ensure stable pages during crc calculations and mmap workloads. We call clear_page_dirty_for_io before we do any crcs, and this forces any application with the file mapped to wait for the crc to finish before it is allowed to change the file. With compression on, the clear_page_dirty_for_io step is happening after we've compressed the pages. This means the applications might be changing the pages while we are compressing them, and some of those modifications might not hit the disk. This commit adds the clear_page_dirty_for_io before compression starts and makes sure to redirty the page if we have to fallback to uncompressed IO as well. Signed-off-by: Chris Mason Reported-by: Alexandre Oliva cc: stable@vger.kernel.org --- fs/btrfs/extent_io.c | 33 +++++++++++++++++++++++++++++++++ fs/btrfs/extent_io.h | 2 ++ fs/btrfs/inode.c | 14 ++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index f173c5af6461..cdee391fc7bf 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1257,6 +1257,39 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end) GFP_NOFS); } +int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end) +{ + unsigned long index = start >> PAGE_CACHE_SHIFT; + unsigned long end_index = end >> PAGE_CACHE_SHIFT; + struct page *page; + + while (index <= end_index) { + page = find_get_page(inode->i_mapping, index); + BUG_ON(!page); /* Pages should be in the extent_io_tree */ + clear_page_dirty_for_io(page); + page_cache_release(page); + index++; + } + return 0; +} + +int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end) +{ + unsigned long index = start >> PAGE_CACHE_SHIFT; + unsigned long end_index = end >> PAGE_CACHE_SHIFT; + struct page *page; + + while (index <= end_index) { + page = find_get_page(inode->i_mapping, index); + BUG_ON(!page); /* Pages should be in the extent_io_tree */ + account_page_redirty(page); + __set_page_dirty_nobuffers(page); + page_cache_release(page); + index++; + } + return 0; +} + /* * helper function to set both pages and extents in the tree writeback */ diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 6068a1985560..258c92156857 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -325,6 +325,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, unsigned long *map_len); int extent_range_uptodate(struct extent_io_tree *tree, u64 start, u64 end); +int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); +int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end); int extent_clear_unlock_delalloc(struct inode *inode, struct extent_io_tree *tree, u64 start, u64 end, struct page *locked_page, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1f26888825e2..6a6e13c53086 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -353,6 +353,7 @@ static noinline int compress_file_range(struct inode *inode, int i; int will_compress; int compress_type = root->fs_info->compress_type; + int redirty = 0; /* if this is a small write inside eof, kick off a defrag */ if ((end - start + 1) < 16 * 1024 && @@ -415,6 +416,17 @@ again: if (BTRFS_I(inode)->force_compress) compress_type = BTRFS_I(inode)->force_compress; + /* + * we need to call clear_page_dirty_for_io on each + * page in the range. Otherwise applications with the file + * mmap'd can wander in and change the page contents while + * we are compressing them. + * + * If the compression fails for any reason, we set the pages + * dirty again later on. + */ + extent_range_clear_dirty_for_io(inode, start, end); + redirty = 1; ret = btrfs_compress_pages(compress_type, inode->i_mapping, start, total_compressed, pages, @@ -554,6 +566,8 @@ cleanup_and_bail_uncompressed: __set_page_dirty_nobuffers(locked_page); /* unlocked later on in the async handlers */ } + if (redirty) + extent_range_redirty_for_io(inode, start, end); add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0, BTRFS_COMPRESS_NONE); *num_added += 1; -- cgit v1.2.3 From 36953d98149674d218420e29f3ea2af827a68e74 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 26 Mar 2013 21:22:28 +0530 Subject: ASoC: compress - add support for metadata apis Compress core added metadata apis in 9727b4, so add same in ASoC Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index b5b3db71e253..f9b219772a8d 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -322,11 +322,38 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, return ret; } +static int sst_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) + ret = platform->driver->compr_ops->set_metadata(cstream, metadata); + + return ret; +} + +static int sst_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) + ret = platform->driver->compr_ops->get_metadata(cstream, metadata); + + return ret; +} /* ASoC Compress operations */ static struct snd_compr_ops soc_compr_ops = { .open = soc_compr_open, .free = soc_compr_free, .set_params = soc_compr_set_params, + .set_metadata = sst_compr_set_metadata, + .get_metadata = sst_compr_get_metadata, .get_params = soc_compr_get_params, .trigger = soc_compr_trigger, .pointer = soc_compr_pointer, -- cgit v1.2.3 From 330305cc4a6b0cb75c22fc01b8826f0ad755550f Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sun, 24 Mar 2013 17:36:29 +0000 Subject: ipv4: Fix ip-header identification for gso packets. ip-header id needs to be incremented even if IP_DF flag is set. This behaviour was changed in commit 490ab08127cebc25e3a26 (IP_GRE: Fix IP-Identification). Following patch fixes it so that identification is always incremented. Reported-by: Cong Wang Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/net/ipip.h | 16 ++++++---------- net/ipv4/af_inet.c | 3 +-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/net/ipip.h b/include/net/ipip.h index fd19625ff99d..982141c15200 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -77,15 +77,11 @@ static inline void tunnel_ip_select_ident(struct sk_buff *skb, { struct iphdr *iph = ip_hdr(skb); - if (iph->frag_off & htons(IP_DF)) - iph->id = 0; - else { - /* Use inner packet iph-id if possible. */ - if (skb->protocol == htons(ETH_P_IP) && old_iph->id) - iph->id = old_iph->id; - else - __ip_select_ident(iph, dst, - (skb_shinfo(skb)->gso_segs ?: 1) - 1); - } + /* Use inner packet iph-id if possible. */ + if (skb->protocol == htons(ETH_P_IP) && old_iph->id) + iph->id = old_iph->id; + else + __ip_select_ident(iph, dst, + (skb_shinfo(skb)->gso_segs ?: 1) - 1); } #endif diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 68f6a94f7661..c929d9c1c4b6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1333,8 +1333,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, iph->frag_off |= htons(IP_MF); offset += (skb->len - skb->mac_len - iph->ihl * 4); } else { - if (!(iph->frag_off & htons(IP_DF))) - iph->id = htons(id++); + iph->id = htons(id++); } iph->tot_len = htons(skb->len - skb->mac_len); iph->check = 0; -- cgit v1.2.3 From 1a2c7d568f624307c5821f31e54727a4b374855c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 24 Mar 2013 22:50:23 +0000 Subject: ASoC: arizona: Add delay after powering up line level outputs Ensure that the outputs are fully enabled before we begin passing audio through them. Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index abdd019c5b6e..389f23253831 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -579,6 +579,24 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + case ARIZONA_OUT1R_ENA_SHIFT: + case ARIZONA_OUT2L_ENA_SHIFT: + case ARIZONA_OUT2R_ENA_SHIFT: + case ARIZONA_OUT3L_ENA_SHIFT: + case ARIZONA_OUT3R_ENA_SHIFT: + msleep(17); + break; + + default: + break; + } + break; + } + return 0; } EXPORT_SYMBOL_GPL(arizona_out_ev); -- cgit v1.2.3 From eddc0a3abff273842a94784d2d022bbc36dc9015 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 21 Mar 2013 02:30:41 -0700 Subject: yama: Better permission check for ptraceme Change the permission check for yama_ptrace_ptracee to the standard ptrace permission check, testing if the traceer has CAP_SYS_PTRACE in the tracees user namespace. Reviewed-by: Kees Cook Signed-off-by: "Eric W. Biederman" --- security/yama/yama_lsm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 23414b93771f..13c88fbcf037 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -347,10 +347,8 @@ int yama_ptrace_traceme(struct task_struct *parent) /* Only disallow PTRACE_TRACEME on more aggressive settings. */ switch (ptrace_scope) { case YAMA_SCOPE_CAPABILITY: - rcu_read_lock(); - if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE)) + if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE)) rc = -EPERM; - rcu_read_unlock(); break; case YAMA_SCOPE_NO_ATTACH: rc = -EPERM; -- cgit v1.2.3 From 64a817cfbded8674f345d1117b117f942a351a69 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 26 Mar 2013 14:11:13 -0400 Subject: nfsd4: reject "negative" acl lengths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we only enforce an upper bound, not a lower bound, a "negative" length can get through here. The symptom seen was a warning when we attempt to a kmalloc with an excessive size. Reported-by: Toralf Förster Cc: stable@kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 01168865dd37..a2720071f282 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -264,7 +264,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, iattr->ia_valid |= ATTR_SIZE; } if (bmval[0] & FATTR4_WORD0_ACL) { - int nace; + u32 nace; struct nfs4_ace *ace; READ_BUF(4); len += 4; -- cgit v1.2.3 From 4dcaf47258d59010802bd0eda933f69ee7d98cc7 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Tue, 26 Mar 2013 11:03:07 -0500 Subject: rsxx: enable error return of rsxx_eeh_save_issued_dmas() Commit d8d595df introduced a bug where we did not check for a NULL return from kmalloc(). Make rsxx_eeh_save_issued_dmas() return an error for that case, and make the callers handle that. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/core.c | 19 ++++++++++++++++--- drivers/block/rsxx/dma.c | 6 +++++- drivers/block/rsxx/rsxx_priv.h | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index 93f28191a0ff..5af21f2db29c 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -323,10 +323,11 @@ static int card_shutdown(struct rsxx_cardinfo *card) return 0; } -static void rsxx_eeh_frozen(struct pci_dev *dev) +static int rsxx_eeh_frozen(struct pci_dev *dev) { struct rsxx_cardinfo *card = pci_get_drvdata(dev); int i; + int st; dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n"); @@ -342,7 +343,9 @@ static void rsxx_eeh_frozen(struct pci_dev *dev) pci_disable_device(dev); - rsxx_eeh_save_issued_dmas(card); + st = rsxx_eeh_save_issued_dmas(card); + if (st) + return st; rsxx_eeh_save_issued_creg(card); @@ -356,6 +359,8 @@ static void rsxx_eeh_frozen(struct pci_dev *dev) card->ctrl[i].cmd.buf, card->ctrl[i].cmd.dma_addr); } + + return 0; } static void rsxx_eeh_failure(struct pci_dev *dev) @@ -399,6 +404,8 @@ static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card) static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev, enum pci_channel_state error) { + int st; + if (dev->revision < RSXX_EEH_SUPPORT) return PCI_ERS_RESULT_NONE; @@ -407,7 +414,13 @@ static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev, return PCI_ERS_RESULT_DISCONNECT; } - rsxx_eeh_frozen(dev); + st = rsxx_eeh_frozen(dev); + if (st) { + dev_err(&dev->dev, "Slot reset setup failed\n"); + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; } diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 95047e111a33..7594c6ddc181 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -980,7 +980,7 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card) } } -void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) +int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) { int i; int j; @@ -990,6 +990,8 @@ void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets, GFP_KERNEL); + if (!issued_dmas) + return -ENOMEM; for (i = 0; i < card->n_targets; i++) { INIT_LIST_HEAD(&issued_dmas[i]); @@ -1030,6 +1032,8 @@ void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) } kfree(issued_dmas); + + return 0; } void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card) diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index 8a7ac87f1dc5..382e8bf5c03b 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -381,7 +381,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, rsxx_dma_cb cb, void *cb_data); int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl); -void rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card); +int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card); void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card); int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card); -- cgit v1.2.3 From 80b00df291684850b5659ec95fb1fd2acbd2c0ec Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Tue, 26 Mar 2013 11:06:35 -0500 Subject: rsxx: remove unused variable Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 7594c6ddc181..0607513cfb41 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -1056,7 +1056,6 @@ void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card) int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) { struct rsxx_dma *dma; - struct rsxx_dma *tmp; int i; for (i = 0; i < card->n_targets; i++) { -- cgit v1.2.3 From 637f44d24f8868ee5a597a99e7874fdd150d4cba Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 25 Mar 2013 15:40:05 -0400 Subject: drm/i915: Be sure to turn hsync/vsync back on at crt enable (v2) commit f40ebd6bcbbd0d30591f42dc16be52b5086a366b Author: Patrik Jakobsson Date: Tue Mar 5 14:24:48 2013 +0100 drm/i915: Turn off hsync and vsync on ADPA when disabling crt properly disabled the hsync/vsync logic at disable time, but neglected to re-enable them at enable time. v2: In the enable hook, restore the connector's expected DPMS level instead of forcing ON. Do this by stashing a back pointer to the connector in the crt (suggested by danvet) since otherwise it's awkward to look up. Signed-off-by: Adam Jackson Cc: stable@vger.kernel.org [danvet: Added more verbose commit citation and cc: stable tag. Also, make it compile. Then self-lart and try to assign the right pointer.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 32a3693905ec..1ce45a0a2d3e 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -45,6 +45,9 @@ struct intel_crt { struct intel_encoder base; + /* DPMS state is stored in the connector, which we need in the + * encoder's enable/disable callbacks */ + struct intel_connector *connector; bool force_hotplug_required; u32 adpa_reg; }; @@ -81,29 +84,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, return true; } -static void intel_disable_crt(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 temp; - - temp = I915_READ(crt->adpa_reg); - temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; - temp &= ~ADPA_DAC_ENABLE; - I915_WRITE(crt->adpa_reg, temp); -} - -static void intel_enable_crt(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 temp; - - temp = I915_READ(crt->adpa_reg); - temp |= ADPA_DAC_ENABLE; - I915_WRITE(crt->adpa_reg, temp); -} - /* Note: The caller is required to filter out dpms modes not supported by the * platform. */ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) @@ -135,6 +115,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) I915_WRITE(crt->adpa_reg, temp); } +static void intel_disable_crt(struct intel_encoder *encoder) +{ + intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void intel_enable_crt(struct intel_encoder *encoder) +{ + struct intel_crt *crt = intel_encoder_to_crt(encoder); + + intel_crt_set_dpms(encoder, crt->connector->base.dpms); +} + + static void intel_crt_dpms(struct drm_connector *connector, int mode) { struct drm_device *dev = connector->dev; @@ -746,6 +739,7 @@ void intel_crt_init(struct drm_device *dev) } connector = &intel_connector->base; + crt->connector = intel_connector; drm_connector_init(dev, &intel_connector->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); -- cgit v1.2.3 From a1422b8cb443c6cfc58da38394673b8b8eda6458 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:27:13 -0700 Subject: ASoC: snd_soc_register_component() uses properly snd_soc_register_dai[s]() snd_soc_register_dai() uses fmt_single_name(), and snd_soc_register_dais() uses fmt_multiple_name() for dai->name which is used for name based matching. This patch uses properly snd_soc_register_dai() it it was single driver, and uses snd_register_dais() if it were multiple drivers. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9e6118573fef..2ecaaf13e319 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4169,7 +4169,15 @@ int snd_soc_register_component(struct device *dev, cmpnt->driver = cmpnt_drv; cmpnt->num_dai = num_dai; - ret = snd_soc_register_dais(dev, dai_drv, num_dai); + /* + * snd_soc_register_dai() uses fmt_single_name(), and + * snd_soc_register_dais() uses fmt_multiple_name() + * for dai->name which is used for name based matching + */ + if (1 == num_dai) + ret = snd_soc_register_dai(dev, dai_drv); + else + ret = snd_soc_register_dais(dev, dai_drv, num_dai); if (ret < 0) { dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); goto error_component_name; -- cgit v1.2.3 From bfcb921caf37ceccb4bb474d7f426f016bf81efa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:30:54 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on davinci i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 821831207180..ebe82947bab3 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = { }; +static const struct snd_soc_component_driver davinci_i2s_component = { + .name = "davinci-i2s", +}; + static int davinci_i2s_probe(struct platform_device *pdev) { struct snd_platform_data *pdata = pdev->dev.platform_data; @@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, + &davinci_i2s_dai, 1); if (ret != 0) goto err_release_clk; ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); clk_put(dev->clk); @@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev) { struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); clk_disable(dev->clk); -- cgit v1.2.3 From ee226ce19557cd5dce12f818462c9c331570cac6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:31:07 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on davinci vcif Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-vcif.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 07bde2e6f84e..30587c0cdbd2 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = { }; +static const struct snd_soc_component_driver davinci_vcif_component = { + .name = "davinci-vcif", +}; + static int davinci_vcif_probe(struct platform_device *pdev) { struct davinci_vc *davinci_vc = pdev->dev.platform_data; @@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, davinci_vcif_dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai); + ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component, + &davinci_vcif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "could not register dai\n"); return ret; @@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } @@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) static int davinci_vcif_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); return 0; -- cgit v1.2.3 From eeef0eda7ac42b19a17cc3de8f826a160f1f102e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:31:19 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on davinci mcasp Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 9321e5c9d8c1..c2e67f1f194c 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -962,6 +962,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }; +static const struct snd_soc_component_driver davinci_mcasp_component = { + .name = "davinci-mcasp", +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -1170,7 +1174,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]); + ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) goto err_release_clk; @@ -1178,13 +1183,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_release_clk: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1194,7 +1199,7 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); -- cgit v1.2.3 From 92eaa328f2789c65441a85d50b5acea1375cb692 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:31:30 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on dw i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/dwc/designware_i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index deb30d59965e..593a3ea12d4c 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = { .trigger = dw_i2s_trigger, }; +static const struct snd_soc_component_driver dw_i2s_component = { + .name = "dw-i2s", +}; + #ifdef CONFIG_PM static int dw_i2s_suspend(struct snd_soc_dai *dai) @@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, + dw_i2s_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); goto err_set_drvdata; @@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev) { struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(dev->clk); -- cgit v1.2.3 From f298a0ffa4b6169d665721962cd0723e34078be0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:31:41 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on mpc5200 ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_ac97.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index a4aec0488dd3..4141b35ef0bb 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = { .ops = &psc_ac97_digital_ops, } }; +static const struct snd_soc_component_driver psc_ac97_component = { + .name = DRV_NAME, +}; /* --------------------------------------------------------------------- @@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op) if (rc != 0) return rc; - rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); + rc = snd_soc_register_component(&op->dev, &psc_ac97_component, + psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); if (rc != 0) { dev_err(&op->dev, "Failed to register DAI\n"); return rc; @@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op) static int psc_ac97_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai)); + snd_soc_unregister_component(&op->dev); return 0; } -- cgit v1.2.3 From a2c662c0e5df335010a9bfa1a0c43332fadebe4b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:28:24 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on atmel ssc Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index e13580d6c476..1435f3067d16 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -707,13 +707,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .ops = &atmel_ssc_dai_ops, }; +static const struct snd_soc_component_driver atmel_ssc_component = { + .name = "atmel-ssc", +}; + static int asoc_ssc_init(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct ssc_device *ssc = platform_get_drvdata(pdev); int ret; - ret = snd_soc_register_dai(dev, &atmel_ssc_dai); + ret = snd_soc_register_component(dev, &atmel_ssc_component, + &atmel_ssc_dai, 1); if (ret) { dev_err(dev, "Could not register DAI: %d\n", ret); goto err; @@ -732,7 +737,7 @@ static int asoc_ssc_init(struct device *dev) return 0; err_unregister_dai: - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); err: return ret; } @@ -747,7 +752,7 @@ static void asoc_ssc_exit(struct device *dev) else atmel_pcm_pdc_platform_unregister(dev); - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); } /** -- cgit v1.2.3 From 8b1be63bdfde194b834448e8ef1615c28a6d695c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:28:37 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on au1x i2sc Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/au1x/i2sc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 072448afc219..b3f37f6edbcb 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = { .ops = &au1xi2s_dai_ops, }; +static const struct snd_soc_component_driver au1xi2s_component = { + .name = "au1xi2s", +}; + static int au1xi2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; @@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver); + return snd_soc_register_component(&pdev->dev, &au1xi2s_component, + &au1xi2s_dai_driver, 1); } static int au1xi2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */ -- cgit v1.2.3 From a4ff200c00f836f6d0c4d9ac954596b5df40d157 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:28:50 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on au1x psc-ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/au1x/psc-ac97.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 6ba07e365967..8f1862aa7333 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { .ops = &au1xpsc_ac97_dai_ops, }; +static const struct snd_soc_component_driver au1xpsc_ac97_component = { + .name = "au1xpsc-ac97", +}; + static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; @@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, wd); - ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); + ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component, + &wd->dai_drv, 1); if (ret) return ret; @@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); /* disable PSC completely */ au_writel(0, AC97_CFG(wd)); -- cgit v1.2.3 From 4edf87f5f7984812ce7dfb5320f198e91e60bb9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:29:24 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on au1x psc-i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/au1x/psc-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 360b4e50d7c8..fe923a7bdc39 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { .ops = &au1xpsc_i2s_dai_ops, }; +static const struct snd_soc_component_driver au1xpsc_i2s_component = { + .name = "au1xpsc-i2s", +}; + static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) { struct resource *iores, *dmares; @@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, wd); - return snd_soc_register_dai(&pdev->dev, &wd->dai_drv); + return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component, + &wd->dai_drv, 1); } static int au1xpsc_i2s_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); au_writel(0, I2S_CFG(wd)); au_sync(); -- cgit v1.2.3 From bbedf1b25586d1b148a85600f29aad2241514c6f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:29:34 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on au1x ac97c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/au1x/ac97c.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index ea7d9d157022..44b8dcecf571 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = { .ops = &alchemy_ac97c_ops, }; +static const struct snd_soc_component_driver au1xac97c_component = { + .name = "au1xac97c", +}; + static int au1xac97c_drvprobe(struct platform_device *pdev) { int ret; @@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver); + ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component, + &au1xac97c_dai_driver, 1); if (ret) return ret; @@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev) { struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ -- cgit v1.2.3 From 3272c51bfab7db6e9dfd4deb4b99284abf2ed27c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:29:46 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on bf6xx i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/blackfin/bf6xx-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c index 8f337972f438..c02405cc007d 100644 --- a/sound/soc/blackfin/bf6xx-i2s.c +++ b/sound/soc/blackfin/bf6xx-i2s.c @@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = { .ops = &bfin_i2s_dai_ops, }; +static const struct snd_soc_component_driver bfin_i2s_component = { + .name = "bfin-i2s", +}; + static int bfin_i2s_probe(struct platform_device *pdev) { struct sport_device *sport; @@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev) return -ENODEV; /* register with the ASoC layers */ - ret = snd_soc_register_dai(dev, &bfin_i2s_dai); + ret = snd_soc_register_component(dev, &bfin_i2s_component, + &bfin_i2s_dai, 1); if (ret) { dev_err(dev, "Failed to register DAI: %d\n", ret); sport_delete(sport); @@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev) { struct sport_device *sport = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_delete(sport); return 0; -- cgit v1.2.3 From 514f6ac78b0b915760dd9b0f141504b262fa7ada Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:29:57 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on bf5xx ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 8e41bcb020eb..490217325975 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; +static const struct snd_soc_component_driver bfin_ac97_component = { + .name = "bfin-ac97", +}; + static int asoc_bfin_ac97_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev) goto sport_config_err; } - ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component, + &bfin_ac97_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); goto sport_config_err; @@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -- cgit v1.2.3 From b56733bd2bd05aa28b44d42a807162c0922fc207 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:30:08 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on bf5xx i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 168d88bccb41..dd0c2a4f83a3 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { .ops = &bf5xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver bf5xx_i2s_component = { + .name = "bf5xx-i2s", +}; + static int bf5xx_i2s_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev) return -ENODEV; /* register with the ASoC layers */ - ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component, + &bf5xx_i2s_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); sport_done(sport_handle); @@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev) pr_debug("%s enter\n", __func__); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); return 0; -- cgit v1.2.3 From 58309649b4feadea44c5cc3e5d410c34d81ef5d1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:30:20 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on bf5xx tdm Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-tdm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index c1e516ec53ad..69e9a3e935bd 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = { .ops = &bf5xx_tdm_dai_ops, }; +static const struct snd_soc_component_driver bf5xx_tdm_component = { + .name = "bf5xx-tdm", +}; + static int bfin_tdm_probe(struct platform_device *pdev) { struct sport_device *sport_handle; @@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev) goto sport_config_err; } - ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai); + ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component, + &bf5xx_tdm_dai, 1); if (ret) { pr_err("Failed to register DAI: %d\n", ret); goto sport_config_err; @@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev) { struct sport_device *sport_handle = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); sport_done(sport_handle); return 0; -- cgit v1.2.3 From 426c340853da49e7c55fe856408ea44f8852d8c8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:30:32 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on ep93xx ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-ac97.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 1738d28fb04f..e593c1e4e1dd 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -353,6 +353,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = { .ops = &ep93xx_ac97_dai_ops, }; +static const struct snd_soc_component_driver ep93xx_ac97_component = { + .name = "ep93xx-ac97", +}; + static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; @@ -390,7 +394,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) ep93xx_ac97_info = info; platform_set_drvdata(pdev, info); - ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component, + &ep93xx_ac97_dai, 1); if (ret) goto fail; @@ -407,7 +412,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev) { struct ep93xx_ac97_info *info = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); /* disable the AC97 controller */ ep93xx_ac97_write_reg(info, AC97GCR, 0); -- cgit v1.2.3 From ec05085170fcac5cba66306155083f120dec6ff6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:30:43 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on ep93xx i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 323ed69b7975..8d244be275d6 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = { .ops = &ep93xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver ep93xx_i2s_component = { + .name = "ep93xx-i2s", +}; + static int ep93xx_i2s_probe(struct platform_device *pdev) { struct ep93xx_i2s_info *info; @@ -405,7 +409,8 @@ static int ep93xx_i2s_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, info); info->dma_params = ep93xx_i2s_dma_params; - err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai); + err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component, + &ep93xx_i2s_dai, 1); if (err) goto fail_put_lrclk; @@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev) { struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(info->lrclk); clk_put(info->sclk); -- cgit v1.2.3 From f200c02beb5ddf4d886b4aca53f9f9f8bf332d06 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:31:53 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on mpc5200 i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index b95b966f25a0..f4efaadb80a2 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{ .ops = &psc_i2s_dai_ops, } }; +static const struct snd_soc_component_driver psc_i2s_component = { + .name = "mpc5200-i2s", +}; + /* --------------------------------------------------------------------- * OF platform bus binding code: * - Probe/remove operations @@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op) if (rc != 0) return rc; - rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); + rc = snd_soc_register_component(&op->dev, &psc_i2s_component, + psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); return rc; @@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op) static int psc_i2s_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai)); + snd_soc_unregister_component(&op->dev); return 0; } -- cgit v1.2.3 From 3580aa10fbb3a0ffbca9853dc827ea84f1073748 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:32:04 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on fsl ssi Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7decbd9b2340..fe04c67f8fb8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -574,6 +574,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { .ops = &fsl_ssi_dai_ops, }; +static const struct snd_soc_component_driver fsl_ssi_component = { + .name = "fsl-ssi", +}; + /* Show the statistics of a flag only if its interrupt is enabled. The * compiler will optimze this code to a no-op if the interrupt is not * enabled. @@ -782,7 +786,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Register with ASoC */ dev_set_drvdata(&pdev->dev, ssi_private); - ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv); + ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, + &ssi_private->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); goto error_dev; @@ -835,7 +840,7 @@ done: error_dai: if (ssi_private->ssi_on_imx) platform_device_unregister(ssi_private->imx_pcm_pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); error_dev: dev_set_drvdata(&pdev->dev, NULL); @@ -873,7 +878,7 @@ static int fsl_ssi_remove(struct platform_device *pdev) clk_disable_unprepare(ssi_private->clk); clk_put(ssi_private->clk); } - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); device_remove_file(&pdev->dev, &ssi_private->dev_attr); free_irq(ssi_private->irq, ssi_private); -- cgit v1.2.3 From c22fd5ef0fcccc8e960f307893fc5b3de68512d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:32:15 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on imx ssi Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/imx-ssi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 55464a5b0706..90110ada270d 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -413,6 +413,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = { .ops = &imx_ssi_pcm_dai_ops, }; +static const struct snd_soc_component_driver imx_component = { + .name = DRV_NAME, +}; + static void setup_channel_to_ac97(struct imx_ssi *imx_ssi) { void __iomem *base = imx_ssi->base; @@ -586,7 +590,8 @@ static int imx_ssi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ssi); - ret = snd_soc_register_dai(&pdev->dev, dai); + ret = snd_soc_register_component(&pdev->dev, &imx_component, + dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); goto failed_register; @@ -627,7 +632,7 @@ failed_pdev_alloc: failed_pdev_fiq_add: platform_device_put(ssi->soc_platform_pdev_fiq); failed_pdev_fiq_alloc: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); failed_register: release_mem_region(res->start, resource_size(res)); failed_get_resource: @@ -645,7 +650,7 @@ static int imx_ssi_remove(struct platform_device *pdev) platform_device_unregister(ssi->soc_platform_pdev); platform_device_unregister(ssi->soc_platform_pdev_fiq); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; -- cgit v1.2.3 From 29cc15cfd2db4045d1c89d867d05bce6db76037e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:32:28 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on jz4740 i2s Signed-off-by: Kuninori Morimoto Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 6cef491f4823..9a126441c5f3 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = { .resume = jz4740_i2s_resume, }; +static const struct snd_soc_component_driver jz4740_i2s_component = { + .name = "jz4740-i2s", +}; + static int jz4740_i2s_dev_probe(struct platform_device *pdev) { struct jz4740_i2s *i2s; @@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, i2s); - ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component, + &jz4740_i2s_dai, 1); if (ret) { dev_err(&pdev->dev, "Failed to register DAI\n"); @@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev) { struct jz4740_i2s *i2s = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); clk_put(i2s->clk_aic); -- cgit v1.2.3 From 83d85f53adf38f5021afd921a84efd53c44aff56 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:32:39 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on kirkwood i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index c74c89065493..befe68f59285 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { .ops = &kirkwood_i2s_dai_ops, }; +static const struct snd_soc_component_driver kirkwood_i2s_component = { + .name = DRV_NAME, +}; + static int kirkwood_i2s_dev_probe(struct platform_device *pdev) { struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; @@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; } - err = snd_soc_register_dai(&pdev->dev, soc_dai); + err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component, + soc_dai, 1); if (!err) return 0; - dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); + dev_err(&pdev->dev, "snd_soc_register_component failed\n"); if (!IS_ERR(priv->extclk)) { clk_disable_unprepare(priv->extclk); @@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev) { struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (!IS_ERR(priv->extclk)) { clk_disable_unprepare(priv->extclk); -- cgit v1.2.3 From b1c36861315ce37c2fee8c1c90433068866a8871 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:32:50 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on sst Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/mid-x86/sst_platform.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index a263cbed8624..31a829cca5ef 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, }; +static const struct snd_soc_component_driver sst_component = { + .name = "sst", +}; + /* helper functions */ static inline void sst_set_stream_status(struct sst_runtime_stream *stream, int state) @@ -683,7 +687,7 @@ static int sst_platform_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_register_dais(&pdev->dev, + ret = snd_soc_register_component(&pdev->dev, &sst_component, sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); if (ret) { pr_err("registering cpu dais failed\n"); @@ -695,7 +699,7 @@ static int sst_platform_probe(struct platform_device *pdev) static int sst_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai)); + snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); pr_debug("sst_platform_remove success\n"); return 0; -- cgit v1.2.3 From 026240bb155bb8f83b9425812f52661fcbaa0629 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:33:02 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on mxs saif Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 3a2aa1d19b93..3e78ba866681 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -627,6 +627,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = { .ops = &mxs_saif_dai_ops, }; +static const struct snd_soc_component_driver mxs_saif_component = { + .name = "mxs-saif", +}; + static irqreturn_t mxs_saif_irq(int irq, void *dev_id) { struct mxs_saif *saif = dev_id; @@ -763,7 +767,8 @@ static int mxs_saif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, saif); - ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); + ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component, + &mxs_saif_dai, 1); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); return ret; @@ -778,7 +783,7 @@ static int mxs_saif_probe(struct platform_device *pdev) return 0; failed_pdev_alloc: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } @@ -786,7 +791,7 @@ failed_pdev_alloc: static int mxs_saif_remove(struct platform_device *pdev) { mxs_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From 7fc34cc3f3c7a0827115bed2139476bc01638a27 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:33:13 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on nuc900 ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 0418467a4848..fe3285ceaf5b 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = { .ops = &nuc900_ac97_dai_ops, }; +static const struct snd_soc_component_driver nuc900_ac97_component = { + .name = "nuc900-ac97", +}; + static int nuc900_ac97_drvprobe(struct platform_device *pdev) { struct nuc900_audio *nuc900_audio; @@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) nuc900_ac97_data = nuc900_audio; - ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai); + ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, + &nuc900_ac97_dai, 1); if (ret) goto out3; @@ -384,7 +389,7 @@ out0: static int nuc900_ac97_drvremove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(nuc900_ac97_data->clk); iounmap(nuc900_ac97_data->mmio); -- cgit v1.2.3 From 43cd814a73903779ab5523ef7a709864456fe9c4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:33:25 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on omap mcbsp Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 8d2defd6fdbe..f51685d72fdb 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -586,6 +586,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = { .ops = &mcbsp_dai_ops, }; +static const struct snd_soc_component_driver omap_mcbsp_component = { + .name = "omap-mcbsp", +}; + static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -793,7 +797,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev) ret = omap_mcbsp_init(pdev); if (!ret) - return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component, + &omap_mcbsp_dai, 1); return ret; } @@ -802,7 +807,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev) { struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(mcbsp->id); -- cgit v1.2.3 From 58709a329eaf4b61bc348305ec387b7964bb0320 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:33:37 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on omap mcpdm Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 5ca11bdac21e..4cc98071aa91 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -420,6 +420,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = { .ops = &omap_mcpdm_dai_ops, }; +static const struct snd_soc_component_driver omap_mcpdm_component = { + .name = "omap-mcpdm", +}; + void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, u8 rx1, u8 rx2) { @@ -480,12 +484,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; - return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); + return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, + &omap_mcpdm_dai, 1); } static int asoc_mcpdm_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From ed22853a5bf51736e5f7e42fddacd053e38ddf01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:33:51 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on omap dmic Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-dmic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index ba49ccd9eed9..4c54542895b0 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -448,6 +448,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = { .ops = &omap_dmic_dai_ops, }; +static const struct snd_soc_component_driver omap_dmic_component = { + .name = "omap-dmic", +}; + static int asoc_dmic_probe(struct platform_device *pdev) { struct omap_dmic *dmic; @@ -507,7 +511,8 @@ static int asoc_dmic_probe(struct platform_device *pdev) goto err_put_clk; } - ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai); + ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component, + &omap_dmic_dai, 1); if (ret) goto err_put_clk; @@ -522,7 +527,7 @@ static int asoc_dmic_remove(struct platform_device *pdev) { struct omap_dmic *dmic = platform_get_drvdata(pdev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(dmic->fclk); return 0; -- cgit v1.2.3 From 0ba7f849eceed0564928f83aa8ec51906e69336d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:01 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on omap hdmi Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index 32fa840c493e..7e120ccc20e1 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -264,6 +264,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = { .ops = &omap_hdmi_dai_ops, }; +static const struct snd_soc_component_driver omap_hdmi_component = { + .name = DRV_NAME, +}; + static int omap_hdmi_probe(struct platform_device *pdev) { int ret; @@ -321,7 +325,8 @@ static int omap_hdmi_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, hdmi_data); - ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); + ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component, + &omap_hdmi_dai, 1); return ret; } @@ -330,7 +335,7 @@ static int omap_hdmi_remove(struct platform_device *pdev) { struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); if (hdmi_data == NULL) { dev_err(&pdev->dev, "cannot obtain HDMi data\n"); -- cgit v1.2.3 From e580f1ced92e0911cce71c3cae7c6e82159c82b4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:12 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on pxa ssp Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d3eb0c2eec77..6f4dd7543e82 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -794,14 +794,19 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { .ops = &pxa_ssp_dai_ops, }; +static const struct snd_soc_component_driver pxa_ssp_component = { + .name = "pxa-ssp", +}; + static int asoc_ssp_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai); + return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, + &pxa_ssp_dai, 1); } static int asoc_ssp_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From ad53232c1f364a1c4172218856c4e44c527b541e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:23 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on pxa2xx ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-ac97.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 88d2cc6a0ae2..57ea8e6c5488 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -233,6 +233,10 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { }, }; +static const struct snd_soc_component_driver pxa_ac97_component = { + .name = "pxa-ac97", +}; + static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { if (pdev->id != -1) { @@ -244,13 +248,13 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) * driver to do interesting things with the clocking to get us up * and running. */ - return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver, - ARRAY_SIZE(pxa_ac97_dai_driver)); + return snd_soc_register_component(&pdev->dev, &pxa_ac97_component, + pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver)); } static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver)); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From bccf7d8bf96bd0c31c94754a2f5e2d1f295df2b7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:37 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on pxa2xx i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 6b1a06f67564..f7ca71664112 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -360,14 +360,19 @@ static struct snd_soc_dai_driver pxa_i2s_dai = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver pxa_i2s_component = { + .name = "pxa-i2s", +}; + static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai); + return snd_soc_register_component(&pdev->dev, &pxa_i2s_component, + &pxa_i2s_dai, 1); } static int pxa2xx_i2s_drv_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From 425f3708949a54aa2f01537eeb6fae33f937279b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:48 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on mmp sspa Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 9140c4abafbc..a64779980177 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -405,6 +405,10 @@ struct snd_soc_dai_driver mmp_sspa_dai = { .ops = &mmp_sspa_dai_ops, }; +static const struct snd_soc_component_driver mmp_sspa_component = { + .name = "mmp-sspa", +}; + static int asoc_mmp_sspa_probe(struct platform_device *pdev) { struct sspa_priv *priv; @@ -450,7 +454,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) priv->dai_fmt = (unsigned int) -1; platform_set_drvdata(pdev, priv); - return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai); + return snd_soc_register_component(&pdev->dev, &mmp_sspa_component, + &mmp_sspa_dai, 1); } static int asoc_mmp_sspa_remove(struct platform_device *pdev) @@ -460,7 +465,7 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev) clk_disable(priv->audio_clk); clk_put(priv->audio_clk); clk_put(priv->sysclk); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From cd5e4d0b2f7065eaef56725ebcd6bf3278d33b20 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:34:59 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on s6000 i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/s6000/s6000-i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index fee4d477a49c..73bb99f0109a 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c @@ -436,6 +436,10 @@ static struct snd_soc_dai_driver s6000_i2s_dai = { .ops = &s6000_i2s_dai_ops, }; +static const struct snd_soc_component_driver s6000_i2s_component = { + .name = "s6000-i2s", +}; + static int s6000_i2s_probe(struct platform_device *pdev) { struct s6000_i2s_dev *dev; @@ -543,7 +547,8 @@ static int s6000_i2s_probe(struct platform_device *pdev) S6_I2S_INT_UNDERRUN | S6_I2S_INT_OVERRUN); - ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component, + &s6000_i2s_dai, 1); if (ret) goto err_release_dev; @@ -572,7 +577,7 @@ static void s6000_i2s_remove(struct platform_device *pdev) struct resource *region; void __iomem *mmio = dev->scbbase; - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); s6000_i2s_stop_channel(dev, 0); s6000_i2s_stop_channel(dev, 1); -- cgit v1.2.3 From 5642ddff274172b42bb9d1f77b75e006a33b65b2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:35:11 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on s3c24xx i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx-i2s.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 13f6dd1ceb00..5403176b2aa3 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -465,11 +465,16 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = { .ops = &s3c24xx_i2s_dai_ops, }; +static const struct snd_soc_component_driver s3c24xx_i2s_component = { + .name = "s3c24xx-i2s", +}; + static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); + ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, + &s3c24xx_i2s_dai, 1); if (ret) { pr_err("failed to register the dai\n"); return ret; @@ -483,14 +488,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return 0; err: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } static int s3c24xx_iis_dev_remove(struct platform_device *pdev) { asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From eca3b01d0885544cbf452c5298afd7c3ccb53a50 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:35:22 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on s3c i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/s3c-i2s-v2.c | 9 +++++---- sound/soc/samsung/s3c-i2s-v2.h | 7 ++++--- sound/soc/samsung/s3c2412-i2s.c | 12 +++++++++--- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 7a73380b3560..20e98d1dded2 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -731,8 +731,9 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #define s3c2412_i2s_resume NULL #endif -int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv) +int s3c_i2sv2_register_component(struct device *dev, int id, + struct snd_soc_component_driver *cmp_drv, + struct snd_soc_dai_driver *dai_drv) { struct snd_soc_dai_ops *ops = drv->ops; @@ -750,8 +751,8 @@ int s3c_i2sv2_register_dai(struct device *dev, int id, drv->suspend = s3c2412_i2s_suspend; drv->resume = s3c2412_i2s_resume; - return snd_soc_register_dai(dev, drv); + return snd_soc_register_component(dev, cmp_drv, dai_drv, 1); } -EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); +EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index f8297d9bb8a3..90abab364b49 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, unsigned long base); /** - * s3c_i2sv2_register_dai - register dai with soc core + * s3c_i2sv2_register_component - register component and dai with soc core * @dev: DAI device * @id: DAI ID * @drv: The driver structure to register @@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * Fill in any missing fields and then register the given dai with the * soc core. */ -extern int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv); +extern int s3c_i2sv2_register_component(struct device *dev, int id, + struct snd_soc_component_driver *cmp_drv, + struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 221337716393..47e23864ea72 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -160,11 +160,17 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = { .ops = &s3c2412_i2s_dai_ops, }; +static const struct snd_soc_component_driver s3c2412_i2s_component = { + .name = "s3c2412-i2s", +}; + static int s3c2412_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); + ret = s3c_i2sv2_register_component(&pdev->dev, -1, + &s3c2412_i2s_component, + &s3c2412_i2s_dai); if (ret) { pr_err("failed to register the dai\n"); return ret; @@ -178,14 +184,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return 0; err: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return ret; } static int s3c2412_iis_dev_remove(struct platform_device *pdev) { asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From 6d717f3ef571e98be54b9f6b12cb5b03fbd515cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:35:33 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on s3c ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/ac97.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 0df3c5644cfa..32ff594954bc 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -370,6 +370,10 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { }, }; +static const struct snd_soc_component_driver s3c_ac97_component = { + .name = "s3c-ac97", +}; + static int s3c_ac97_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; @@ -457,8 +461,8 @@ static int s3c_ac97_probe(struct platform_device *pdev) goto err4; } - ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai, - ARRAY_SIZE(s3c_ac97_dai)); + ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component, + s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); if (ret) goto err5; @@ -470,7 +474,7 @@ static int s3c_ac97_probe(struct platform_device *pdev) return 0; err6: - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); + snd_soc_unregister_component(&pdev->dev); err5: free_irq(irq_res->start, NULL); err4: @@ -490,7 +494,7 @@ static int s3c_ac97_remove(struct platform_device *pdev) struct resource *mem_res, *irq_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); + snd_soc_unregister_component(&pdev->dev); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) -- cgit v1.2.3 From c3764d8bb49dd64be3cba20413ace5887e8dbdcb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:35:44 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on samsung spdif Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/spdif.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 5008e5bd6ed8..2e5ebb2f1982 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -357,6 +357,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = { .resume = spdif_resume, }; +static const struct snd_soc_component_driver samsung_spdif_component = { + .name = "samsung-spdif", +}; + static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; @@ -424,7 +428,8 @@ static int spdif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); - ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai); + ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component, + &samsung_spdif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "fail to register dai\n"); goto err4; @@ -445,7 +450,7 @@ static int spdif_probe(struct platform_device *pdev) return 0; err5: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); err4: iounmap(spdif->regs); err3: @@ -466,7 +471,7 @@ static int spdif_remove(struct platform_device *pdev) struct resource *mem_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); iounmap(spdif->regs); -- cgit v1.2.3 From 4b828535f710604b28d3d9de8916bf99b33817f7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:35:55 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on samsung i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d7231e336a7c..efa73147dfb8 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -963,6 +963,10 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { .delay = i2s_delay, }; +static const struct snd_soc_component_driver samsung_i2s_component = { + .name = "samsung-i2s", +}; + #define SAMSUNG_I2S_RATES SNDRV_PCM_RATE_8000_96000 #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1107,8 +1111,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (samsung_dai_type == TYPE_SEC) { sec_dai = dev_get_drvdata(&pdev->dev); - snd_soc_register_dai(&sec_dai->pdev->dev, - &sec_dai->i2s_dai_drv); + snd_soc_register_component(&sec_dai->pdev->dev, + &samsung_i2s_component, + &sec_dai->i2s_dai_drv, 1); asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1237,7 +1242,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) } } - snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); + snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component, + &pri_dai->i2s_dai_drv, 1); pm_runtime_enable(&pdev->dev); @@ -1276,7 +1282,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) i2s->sec_dai = NULL; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From fc466ba3ee01cef840523f9bbbf6811e111168c3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:36:06 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on samsung pcm Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/pcm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 13bab79ad93d..1566afe9ef52 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -490,6 +490,10 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = { }, }; +static const struct snd_soc_component_driver s3c_pcm_component = { + .name = "s3c-pcm", +}; + static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; @@ -583,7 +587,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]); + ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component, + &s3c_pcm_dai[pdev->id], 1); if (ret != 0) { dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); goto err5; @@ -598,7 +603,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) return 0; err6: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); err5: clk_disable_unprepare(pcm->pclk); clk_put(pcm->pclk); @@ -619,7 +624,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev) struct resource *mem_res; asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 1dfec3954e9884c79ee29c430811264318268365 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:36:17 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on goni_wm8994 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/goni_wm8994.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index d37ede58e0a8..415ad81999c4 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, }; +static const struct snd_soc_component_driver voice_component = { + .name = "goni-voice", +}; + static struct snd_soc_ops goni_voice_ops = { .hw_params = goni_voice_hw_params, }; @@ -270,7 +274,8 @@ static int __init goni_init(void) return -ENOMEM; /* register voice DAI here */ - ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai); + ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component, + &voice_dai, 1); if (ret) { platform_device_put(goni_snd_device); return ret; @@ -280,7 +285,7 @@ static int __init goni_init(void) ret = platform_device_add(goni_snd_device); if (ret) { - snd_soc_unregister_dai(&goni_snd_device->dev); + snd_soc_unregister_component(&goni_snd_device->dev); platform_device_put(goni_snd_device); } @@ -289,7 +294,7 @@ static int __init goni_init(void) static void __exit goni_exit(void) { - snd_soc_unregister_dai(&goni_snd_device->dev); + snd_soc_unregister_component(&goni_snd_device->dev); platform_device_unregister(goni_snd_device); } -- cgit v1.2.3 From cd9003a200ad1fdde20e7e687d8e376b62e171cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:36:27 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on sh4 ssi Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/ssi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index c8e73a703934..e889405ebd38 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -379,15 +379,19 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = { #endif }; +static const struct snd_soc_component_driver sh4_ssi_component = { + .name = "sh4-ssi", +}; + static int sh4_soc_dai_probe(struct platform_device *pdev) { - return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai, - ARRAY_SIZE(sh4_ssi_dai)); + return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); } static int sh4_soc_dai_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai)); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From 73d86d9808ce4885d515a05454a26d5a8533c01a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:36:49 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on sh4 hac Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/hac.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 4cc2d64ef476..af19f77b7bf0 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -310,15 +310,19 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = { #endif }; +static const struct snd_soc_component_driver sh4_hac_component = { + .name = "sh4-hac", +}; + static int hac_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_dais(&pdev->dev, sh4_hac_dai, - ARRAY_SIZE(sh4_hac_dai)); + return snd_soc_register_component(&pdev->dev, &sh4_hac_component, + sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } static int hac_soc_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai)); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From a582d44b1352176df012f512124c4395bb60eaf5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:00 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on spear spdif out Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/spear/spdif_out.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 5eac4cda2fd7..1e3c3dda3598 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -270,6 +270,10 @@ static struct snd_soc_dai_driver spdif_out_dai = { .ops = &spdif_out_dai_ops, }; +static const struct snd_soc_component_driver spdif_out_component = { + .name = "spdif-out", +}; + static int spdif_out_probe(struct platform_device *pdev) { struct spdif_out_dev *host; @@ -314,7 +318,8 @@ static int spdif_out_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, host); - ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai); + ret = snd_soc_register_component(&pdev->dev, &spdif_out_component, + &spdif_out_dai, 1); if (ret != 0) { clk_put(host->clk); return ret; @@ -327,7 +332,7 @@ static int spdif_out_remove(struct platform_device *pdev) { struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(host->clk); -- cgit v1.2.3 From 669b497674b81062a2fbd735a23c7ae48ac43a35 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:11 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on spear spdif in Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index c7c4b20395bb..14d57e89bcba 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -170,6 +170,10 @@ struct snd_soc_dai_driver spdif_in_dai = { .ops = &spdif_in_dai_ops, }; +static const struct snd_soc_component_driver spdif_in_component = { + .name = "spdif-in", +}; + static irqreturn_t spdif_in_irq(int irq, void *arg) { struct spdif_in_dev *host = (struct spdif_in_dev *)arg; @@ -258,7 +262,8 @@ static int spdif_in_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai); + ret = snd_soc_register_component(&pdev->dev, &spdif_in_component, + &spdif_in_dai, 1); if (ret != 0) { clk_put(host->clk); return ret; @@ -271,7 +276,7 @@ static int spdif_in_remove(struct platform_device *pdev) { struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); dev_set_drvdata(&pdev->dev, NULL); clk_put(host->clk); -- cgit v1.2.3 From 65328454fbf7d76dbaadc699c2692366af9fe441 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:22 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on tegra30 i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index f4e1ce82750a..f138d8fea977 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -336,6 +336,10 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver tegra30_i2s_component = { + .name = DRV_NAME, +}; + static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -464,7 +468,8 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); + ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component, + &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -474,13 +479,13 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_i2s_runtime_suspend(&pdev->dev); @@ -501,7 +506,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra30_i2s_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); -- cgit v1.2.3 From 094e1a3d7d7d456b504058ed40ea19d40e05a7ff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:33 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on tegra20 spdif Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 04771d14d343..6fce0be5eaa3 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -182,6 +182,10 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = { .ops = &tegra20_spdif_dai_ops, }; +static const struct snd_soc_component_driver tegra20_spdif_component = { + .name = DRV_NAME, +}; + static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -329,7 +333,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai); + ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, + &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -339,13 +344,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); @@ -366,7 +371,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev) tegra20_spdif_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(spdif->clk_spdif_out); -- cgit v1.2.3 From 359e2cb749a896ab7d2e2320892e6fe8457d1cfc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:44 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on tegra20 ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 15 ++++++++++----- sound/soc/tegra/tegra_wm9712.c | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 336dcdd3e8a4..b5cee92f82e8 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -248,6 +248,10 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = { .ops = &tegra20_ac97_dai_ops, }; +static const struct snd_soc_component_driver tegra20_ac97_component = { + .name = DRV_NAME, +}; + static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -398,7 +402,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ac97->playback_dma_data.width = 32; ac97->playback_dma_data.req_sel = of_dma[1]; - ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1); + ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component, + &tegra20_ac97_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -408,7 +413,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev); @@ -434,8 +439,8 @@ err_asoc_utils_fini: tegra_asoc_utils_fini(&ac97->util_data); err_unregister_pcm: tegra_pcm_platform_unregister(&pdev->dev); -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_clk_put: clk_put(ac97->clk_ac97); err: @@ -447,7 +452,7 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev) struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); tegra_asoc_utils_fini(&ac97->util_data); diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 68d42403d9b5..6839f88167d0 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -55,7 +55,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link tegra_wm9712_dai = { .name = "AC97 HiFi", .stream_name = "AC97 HiFi", - .cpu_dai_name = "tegra-ac97-pcm", + .cpu_dai_name = "tegra20-ac97", .codec_dai_name = "wm9712-hifi", .codec_name = "wm9712-codec", .init = tegra_wm9712_init, -- cgit v1.2.3 From a413a3c282c143da11b7d6dfb859885e5f8b48be Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:37:55 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on tegra20 i2s Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index caa772de5a18..8b1ceb82c86f 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -276,6 +276,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { .symmetric_rates = 1, }; +static const struct snd_soc_component_driver tegra20_i2s_component = { + .name = DRV_NAME, +}; + static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -419,7 +423,8 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); + ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component, + &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -429,13 +434,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_i2s_runtime_suspend(&pdev->dev); @@ -456,7 +461,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev) tegra20_i2s_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); clk_put(i2s->clk_i2s); -- cgit v1.2.3 From b00e2fa1ab1ff4c4ada4324866516c21c7ce5057 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:38:07 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on txx9aclc ac97 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc-ac97.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 16ab69635e2e..8a2840304d28 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -170,6 +170,10 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = { }, }; +static const struct snd_soc_component_driver txx9aclc_ac97_component = { + .name = "txx9aclc-ac97", +}; + static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) { struct txx9aclc_plat_drvdata *drvdata; @@ -205,12 +209,13 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) if (err < 0) return err; - return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai); + return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, + &txx9aclc_ac97_dai, 1); } static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v1.2.3 From 42277bddc6ad7ab31ad51411578e3e0d8d168963 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:38:19 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on ux500 msp Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 94a3e5705aaa..f1e8a5ecb00b 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -768,6 +768,11 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = { }, }; +static const struct snd_soc_component_driver ux500_msp_component = { + .name = "ux500-msp", +}; + + static int ux500_msp_drv_probe(struct platform_device *pdev) { struct ux500_msp_i2s_drvdata *drvdata; @@ -825,8 +830,8 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, drvdata); - ret = snd_soc_register_dai(&pdev->dev, - &ux500_msp_dai_drv[drvdata->msp->id]); + ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component, + &ux500_msp_dai_drv[drvdata->msp->id], 1); if (ret < 0) { dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", __func__, drvdata->msp->id); @@ -844,7 +849,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) return 0; err_reg_plat: - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + snd_soc_unregister_component(&pdev->dev); err_init_msp: clk_put(drvdata->clk); err_clk: @@ -861,7 +866,7 @@ static int ux500_msp_drv_remove(struct platform_device *pdev) ux500_pcm_unregister_platform(pdev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv)); + snd_soc_unregister_component(&pdev->dev); devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); -- cgit v1.2.3 From f53179c026b11bef674d75154f5ea47ca3248ca9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:38:30 -0700 Subject: ASoC: snd_soc_[un]register_dai[s]() become non global function All drivers are using snd_soc_register_component() instead of snd_soc_register_dai[s]() snd_soc_[un]register_dai[s]() are no longer needed Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 8 -------- sound/soc/soc-core.c | 12 ++++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3d84808952b9..ae9a227d35d3 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -95,14 +95,6 @@ struct snd_soc_dai_driver; struct snd_soc_dai; struct snd_ac97_bus_ops; -/* Digital Audio Interface registration */ -int snd_soc_register_dai(struct device *dev, - struct snd_soc_dai_driver *dai_drv); -void snd_soc_unregister_dai(struct device *dev); -int snd_soc_register_dais(struct device *dev, - struct snd_soc_dai_driver *dai_drv, size_t count); -void snd_soc_unregister_dais(struct device *dev, size_t count); - /* Digital Audio Interface clocking API.*/ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ecaaf13e319..f6cda7b6ce44 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3739,7 +3739,7 @@ static inline char *fmt_multiple_name(struct device *dev, * * @dai: DAI to register */ -int snd_soc_register_dai(struct device *dev, +static int snd_soc_register_dai(struct device *dev, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_codec *codec; @@ -3786,14 +3786,13 @@ int snd_soc_register_dai(struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_register_dai); /** * snd_soc_unregister_dai - Unregister a DAI from the ASoC core * * @dai: DAI to unregister */ -void snd_soc_unregister_dai(struct device *dev) +static void snd_soc_unregister_dai(struct device *dev) { struct snd_soc_dai *dai; @@ -3812,7 +3811,6 @@ found: kfree(dai->name); kfree(dai); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_register_dais - Register multiple DAIs with the ASoC core @@ -3820,7 +3818,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * @dai: Array of DAIs to register * @count: Number of DAIs */ -int snd_soc_register_dais(struct device *dev, +static int snd_soc_register_dais(struct device *dev, struct snd_soc_dai_driver *dai_drv, size_t count) { struct snd_soc_codec *codec; @@ -3884,7 +3882,6 @@ err: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_dais); /** * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core @@ -3892,14 +3889,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais); * @dai: Array of DAIs to unregister * @count: Number of DAIs */ -void snd_soc_unregister_dais(struct device *dev, size_t count) +static void snd_soc_unregister_dais(struct device *dev, size_t count) { int i; for (i = 0; i < count; i++) snd_soc_unregister_dai(dev); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); /** * snd_soc_register_platform - Register a platform with the ASoC core -- cgit v1.2.3 From 0a09dfa04177df5a2e9eeeeaf527efd35c531d11 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 22 Mar 2013 00:54:50 -0700 Subject: ASoC: switch over to use snd_soc_register_component() on sh4 siu siu_dai.c is using snd_soc_register_dais(), even though array size of siu_i2s_dai is 1. OTOH, new API snd_soc_register_component() uses properly snd_soc_register_dai() (henceforth dai()) or snd_soc_register_dais() (henceforth dais()) via num_dai. Then, cpu_dai_name will be "siu-i2s-dai" if dais() was used, and it will be "siu-pcm-audio" if dai() was used. Therefore this patch fixup migor_dai :: cpu_dai_name too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/migor.c | 2 +- sound/soc/sh/siu_dai.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c index 8526e1edaf45..5014a884afee 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/sh/migor.c @@ -153,7 +153,7 @@ static int migor_dai_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link migor_dai = { .name = "wm8978", .stream_name = "WM8978", - .cpu_dai_name = "siu-i2s-dai", + .cpu_dai_name = "siu-pcm-audio", .codec_dai_name = "wm8978-hifi", .platform_name = "siu-pcm-audio", .codec_name = "wm8978.0-001a", diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index 34facdc9e4ac..9dc24ffa892a 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -726,6 +726,10 @@ static struct snd_soc_dai_driver siu_i2s_dai = { .ops = &siu_dai_ops, }; +static const struct snd_soc_component_driver siu_i2s_component = { + .name = "siu-i2s", +}; + static int siu_probe(struct platform_device *pdev) { const struct firmware *fw_entry; @@ -783,7 +787,8 @@ static int siu_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, info); /* register using ARRAY version so we can keep dai name */ - ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1); + ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component, + &siu_i2s_dai, 1); if (ret < 0) goto edaiinit; @@ -796,7 +801,7 @@ static int siu_probe(struct platform_device *pdev) return ret; esocregp: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); edaiinit: iounmap(info->reg); emapreg: @@ -823,7 +828,7 @@ static int siu_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); iounmap(info->reg); iounmap(info->yram); -- cgit v1.2.3 From 7ea600b5314529f9d1b9d6d3c41cb26fce6a7a4a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Mar 2013 18:25:57 -0400 Subject: Nest rename_lock inside vfsmount_lock ... lest we get livelocks between path_is_under() and d_path() and friends. The thing is, wrt fairness lglocks are more similar to rwsems than to rwlocks; it is possible to have thread B spin on attempt to take lock shared while thread A is already holding it shared, if B is on lower-numbered CPU than A and there's a thread C spinning on attempt to take the same lock exclusive. As the result, we need consistent ordering between vfsmount_lock (lglock) and rename_lock (seq_lock), even though everything that takes both is going to take vfsmount_lock only shared. Spotted-by: Brad Spengler Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- fs/dcache.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index fbfae008ba44..e8bc3420d63e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2542,7 +2542,6 @@ static int prepend_path(const struct path *path, bool slash = false; int error = 0; - br_read_lock(&vfsmount_lock); while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; @@ -2572,8 +2571,6 @@ static int prepend_path(const struct path *path, if (!error && !slash) error = prepend(buffer, buflen, "/", 1); -out: - br_read_unlock(&vfsmount_lock); return error; global_root: @@ -2590,7 +2587,7 @@ global_root: error = prepend(buffer, buflen, "/", 1); if (!error) error = is_mounted(vfsmnt) ? 1 : 2; - goto out; + return error; } /** @@ -2617,9 +2614,11 @@ char *__d_path(const struct path *path, int error; prepend(&res, &buflen, "\0", 1); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = prepend_path(path, root, &res, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) return ERR_PTR(error); @@ -2636,9 +2635,11 @@ char *d_absolute_path(const struct path *path, int error; prepend(&res, &buflen, "\0", 1); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = prepend_path(path, &root, &res, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error > 1) error = -EINVAL; @@ -2702,11 +2703,13 @@ char *d_path(const struct path *path, char *buf, int buflen) return path->dentry->d_op->d_dname(path->dentry, buf, buflen); get_fs_root(current->fs, &root); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = path_with_deleted(path, &root, &res, &buflen); + write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) res = ERR_PTR(error); - write_sequnlock(&rename_lock); path_put(&root); return res; } @@ -2830,6 +2833,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) get_fs_root_and_pwd(current->fs, &root, &pwd); error = -ENOENT; + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; @@ -2839,6 +2843,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) prepend(&cwd, &buflen, "\0", 1); error = prepend_path(&pwd, &root, &cwd, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) goto out; @@ -2859,6 +2864,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) } } else { write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); } out: -- cgit v1.2.3 From 2e1cc199fc8666ac5fda200e8a99f1e4dea07175 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Mar 2013 16:38:19 -0600 Subject: ASoC: export snd_soc_register_component Without this, modules will fail to link against those symbols. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f6cda7b6ce44..fb50e00a71e4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4192,6 +4192,7 @@ error_component_name: return ret; } +EXPORT_SYMBOL_GPL(snd_soc_register_component); /** * snd_soc_unregister_component - Unregister a component from the ASoC core @@ -4217,6 +4218,7 @@ found: dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); kfree(cmpnt->name); } +EXPORT_SYMBOL_GPL(snd_soc_unregister_component); /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, -- cgit v1.2.3 From 469dd1c4ac0869cf7d1f87eac9b5a93865c10b76 Mon Sep 17 00:00:00 2001 From: Fabio Valentini Date: Mon, 11 Mar 2013 19:16:34 +0000 Subject: ACPI / PM: fix suspend and resume on Sony Vaio VGN-FW21M Add Sony Vaio VGN-FW21M to the device blacklist in drivers/acpi/sleep.c. Fixes suspend/resume on this device (device no longer reboots instead of resuming). References: https://bugzilla.kernel.org/show_bug.cgi?id=55001 Signed-off-by: Fabio Valentini Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 24213033fbae..9c1a435d10e6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -193,6 +193,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW21M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VPCEB17FX", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), -- cgit v1.2.3 From aaf9d93be71c68558c25b4052ac979ee6b7eb809 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Tue, 19 Mar 2013 06:48:07 +0000 Subject: ACPI / APEI: fix error status check condition for CPER In Table 18-289, ACPI5.0 SPEC, the error data length in CPER Generic Error Data Entry can be 0, which means this generic error data entry can have only one header. So fix the check conditon for it. Signed-off-by: Chen Gong Reviewed-by: Huang Ying Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/cper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index 1e5d8a40101e..fefc2ca7cc3e 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c @@ -405,7 +405,7 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus) return rc; data_len = estatus->data_length; gdata = (struct acpi_hest_generic_data *)(estatus + 1); - while (data_len > sizeof(*gdata)) { + while (data_len >= sizeof(*gdata)) { gedata_len = gdata->error_data_length; if (gedata_len > data_len - sizeof(*gdata)) return -EINVAL; -- cgit v1.2.3 From b8b6611048b7b57b86fbdc9153649ad4dc52135f Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 11 Mar 2013 05:05:16 +0000 Subject: PCI / ACPI: hold acpi_scan_lock during root bus hotplug During merging the PCI tree with the PM/ACPI tree, Linus noticed that we don't use the same lock using patten about ACPI PCI root as acpiphp. Here apply the same locking patten, and we need to execute acpi_bus_hot_remove_device() via acpi_os_hotplug_execute() as it also holds acpi_scan_lock. [rjw: Changelog] Reported-by: Linus Torvalds Signed-off-by: Yinghai Lu No-objection-from: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0ac546d5e53f..5ff173066127 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -646,6 +646,7 @@ static void handle_root_bridge_insertion(acpi_handle handle) static void handle_root_bridge_removal(struct acpi_device *device) { + acpi_status status; struct acpi_eject_event *ej_event; ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); @@ -661,7 +662,9 @@ static void handle_root_bridge_removal(struct acpi_device *device) ej_event->device = device; ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; - acpi_bus_hot_remove_device(ej_event); + status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); + if (ACPI_FAILURE(status)) + kfree(ej_event); } static void _handle_hotplug_event_root(struct work_struct *work) @@ -676,8 +679,9 @@ static void _handle_hotplug_event_root(struct work_struct *work) handle = hp_work->handle; type = hp_work->type; - root = acpi_pci_find_root(handle); + acpi_scan_lock_acquire(); + root = acpi_pci_find_root(handle); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@ -711,6 +715,7 @@ static void _handle_hotplug_event_root(struct work_struct *work) break; } + acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ kfree(buffer.pointer); } -- cgit v1.2.3 From fffe01f7a768d07cc50ace71abe28fbf2f786a43 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 26 Mar 2013 17:25:54 -0400 Subject: PCI: Add PCI ROM helper for platform-provided ROM images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that some UEFI systems provide apparently an apparently valid PCI ROM BAR that turns out to contain garbage, so the attempt in 547b52463 to prefer the ROM from the BAR actually breaks a different set of machines. As Linus pointed out, the graphics drivers are probably in the best position to make this judgement, so this basically reverts 547b52463 and f9a37be0f and adds a new helper function. Followup patches will add support to nouveau and radeon for probing this ROM source if they can't find a ROM from some other source. [bhelgaas: added reporter and bugzilla pointers, s/f4eb5ff05/547b52463] Reference: https://bugzilla.redhat.com/show_bug.cgi?id=927451 Reference: http://lkml.kernel.org/r/kg69ef$vdb$1@ger.gmane.org Reported-by: Mantas Mikulėnas Reported-by: Chris Murphy Signed-off-by: Matthew Garrett Signed-off-by: Bjorn Helgaas --- drivers/pci/rom.c | 67 +++++++++++++++++++++++++---------------------------- include/linux/pci.h | 1 + 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index b41ac7756a4b..c5d0a08a8747 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -100,27 +100,6 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) return min((size_t)(image - rom), size); } -static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size) -{ - struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; - loff_t start; - - /* assign the ROM an address if it doesn't have one */ - if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE)) - return 0; - start = pci_resource_start(pdev, PCI_ROM_RESOURCE); - *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); - - if (*size == 0) - return 0; - - /* Enable ROM space decodes */ - if (pci_enable_rom(pdev)) - return 0; - - return start; -} - /** * pci_map_rom - map a PCI ROM to kernel space * @pdev: pointer to pci device struct @@ -135,7 +114,7 @@ static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size) void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; - loff_t start = 0; + loff_t start; void __iomem *rom; /* @@ -154,21 +133,21 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) return (void __iomem *)(unsigned long) pci_resource_start(pdev, PCI_ROM_RESOURCE); } else { - start = pci_find_rom(pdev, size); - } - } + /* assign the ROM an address if it doesn't have one */ + if (res->parent == NULL && + pci_assign_resource(pdev,PCI_ROM_RESOURCE)) + return NULL; + start = pci_resource_start(pdev, PCI_ROM_RESOURCE); + *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); + if (*size == 0) + return NULL; - /* - * Some devices may provide ROMs via a source other than the BAR - */ - if (!start && pdev->rom && pdev->romlen) { - *size = pdev->romlen; - return phys_to_virt(pdev->rom); + /* Enable ROM space decodes */ + if (pci_enable_rom(pdev)) + return NULL; + } } - if (!start) - return NULL; - rom = ioremap(start, *size); if (!rom) { /* restore enable if ioremap fails */ @@ -202,8 +181,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) return; - if (!pdev->rom || !pdev->romlen) - iounmap(rom); + iounmap(rom); /* Disable again before continuing, leave enabled if pci=rom */ if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) @@ -227,7 +205,24 @@ void pci_cleanup_rom(struct pci_dev *pdev) } } +/** + * pci_platform_rom - provides a pointer to any ROM image provided by the + * platform + * @pdev: pointer to pci device struct + * @size: pointer to receive size of pci window over ROM + */ +void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size) +{ + if (pdev->rom && pdev->romlen) { + *size = pdev->romlen; + return phys_to_virt((phys_addr_t)pdev->rom); + } + + return NULL; +} + EXPORT_SYMBOL(pci_map_rom); EXPORT_SYMBOL(pci_unmap_rom); EXPORT_SYMBOL_GPL(pci_enable_rom); EXPORT_SYMBOL_GPL(pci_disable_rom); +EXPORT_SYMBOL(pci_platform_rom); diff --git a/include/linux/pci.h b/include/linux/pci.h index 2461033a7987..710067f3618c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -916,6 +916,7 @@ void pci_disable_rom(struct pci_dev *pdev); void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); +void __iomem __must_check *pci_platform_rom(struct pci_dev *pdev, size_t *size); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); -- cgit v1.2.3 From e8cd81693bbbb15db57d3c9aa7dd90eda4842874 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 26 Mar 2013 20:30:17 -0400 Subject: vt: synchronize_rcu() under spinlock is not nice... vcs_poll_data_free() calls unregister_vt_notifier(), which calls atomic_notifier_chain_unregister(), which calls synchronize_rcu(). Do it *after* we'd dropped ->f_lock. Cc: stable@vger.kernel.org (all kernels since 2.6.37) Signed-off-by: Al Viro --- drivers/tty/vt/vc_screen.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index e4ca345873c3..d7799deacb21 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll) static struct vcs_poll_data * vcs_poll_data_get(struct file *file) { - struct vcs_poll_data *poll = file->private_data; + struct vcs_poll_data *poll = file->private_data, *kill = NULL; if (poll) return poll; @@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file) file->private_data = poll; } else { /* someone else raced ahead of us */ - vcs_poll_data_free(poll); + kill = poll; poll = file->private_data; } spin_unlock(&file->f_lock); + if (kill) + vcs_poll_data_free(kill); return poll; } -- cgit v1.2.3 From ff931c821bab6713a52b768b0cd7ee7e90713b36 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 21 Mar 2013 16:34:52 +0530 Subject: ARM: OMAP: clocks: Delay clk inits atleast until slab is initialized clk inits on OMAP happen quite early, even before slab is available. The dependency comes from the fact that the timer init code starts to use clocks and hwmod and we need clocks to be initialized by then. There are various problems doing clk inits this early, one is, not being able to do dynamic clk registrations and hence the dependency on clk-private.h. The other is, inability to debug early kernel crashes without enabling DEBUG_LL and earlyprintk. Doing early clk init also exposed another instance of a kernel panic due to a BUG() when CONFIG_DEBUG_SLAB is enabled. [ 0.000000] Kernel BUG at c01174f8 [verbose debug info unavailable] [ 0.000000] Internal error: Oops - BUG: 0 [#1] SMP ARM [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 Not tainted (3.9.0-rc1-12179-g72d48f9 #6) [ 0.000000] PC is at __kmalloc+0x1d4/0x248 [ 0.000000] LR is at __clk_init+0x2e0/0x364 [ 0.000000] pc : [] lr : [] psr: 600001d3 [ 0.000000] sp : c076ff28 ip : c065cefc fp : c0441f54 [ 0.000000] r10: 0000001c r9 : 000080d0 r8 : c076ffd4 [ 0.000000] r7 : c074b578 r6 : c0794d88 r5 : 00000040 r4 : 00000000 [ 0.000000] r3 : 00000000 r2 : c07cac70 r1 : 000080d0 r0 : 0000001c [ 0.000000] Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel [ 0.000000] Control: 10c53c7d Table: 8000404a DAC: 00000017 [ 0.000000] Process swapper (pid: 0, stack limit = 0xc076e240) [ 0.000000] Stack: (0xc076ff28 to 0xc0770000) [ 0.000000] ff20: 22222222 c0794ec8 c06546e8 00000000 00000040 c0794d88 [ 0.000000] ff40: c074b578 c076ffd4 c07951c8 c076e000 00000000 c0441f54 c074b578 c076ffd4 [ 0.000000] ff60: c0793828 00000040 c0794d88 c074b578 c076ffd4 c0776900 c076e000 c07272ac [ 0.000000] ff80: 2f800000 c074c968 c07f93d0 c0719780 c076ffa0 c076ff98 00000000 00000000 [ 0.000000] ffa0: 00000000 00000000 00000000 00000001 c074cd6c c077b1ec 8000406a c0715724 [ 0.000000] ffc0: 00000000 00000000 00000000 00000000 00000000 c074c968 10c53c7d c0776974 [ 0.000000] ffe0: c074cd6c c077b1ec 8000406a 411fc092 00000000 80008074 00000000 00000000 [ 0.000000] [] (__kmalloc+0x1d4/0x248) from [] (__clk_init+0x2e0/0x364) [ 0.000000] [] (__clk_init+0x2e0/0x364) from [] (omap4xxx_clk_init+0xbc/0x140) [ 0.000000] [] (omap4xxx_clk_init+0xbc/0x140) from [] (setup_arch+0x15c/0x284) [ 0.000000] [] (setup_arch+0x15c/0x284) from [] (start_kernel+0x7c/0x334) [ 0.000000] [] (start_kernel+0x7c/0x334) from [<80008074>] (0x80008074) [ 0.000000] Code: e5883004 e1a00006 e28dd00c e8bd8ff0 (e7f001f2) [ 0.000000] ---[ end trace 1b75b31a2719ed1c ]--- [ 0.000000] Kernel panic - not syncing: Attempted to kill the idle task! It was a know issue, that slab allocations would fail when common clock core tries to cache parent pointers for mux clocks on OMAP, and hence a patch 'clk: Allow late cache allocation for clk->parents, commit 7975059d' was added to work this problem around. A BUG() within kmalloc() with CONFIG_DEBUG_SLAB enabled was completely overlooked causing this regression. More details on the issue reported can be found here, http://www.mail-archive.com/linux-omap@vger.kernel.org/msg85932.html With all these issues around clk inits happening way too early, it makes sense to at least move them to a point where dynamic memory allocations are possible. So move them to a point just before the timer code starts using clocks and hwmod. This should at least pave way for clk inits on OMAP moving to dynamic clock registrations instead of using the static macros defined in clk-private.h. The issue with kernel panic while CONFIG_DEBUG_SLAB is enabled was reported by Piotr Haber and Tony Lindgren and this patch fixes the reported issue as well. Reported-by: Piotr Haber Reported-by: Tony Lindgren Signed-off-by: Rajendra Nayak Acked-by: Santosh Shilimkar Reviewed-by: Mike Turquette Acked-by: Paul Walmsley Cc: stable@vger.kernel.org # v3.8 Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/common.h | 3 +++ arch/arm/mach-omap2/io.c | 18 ++++++++++++------ arch/arm/mach-omap2/timer.c | 4 ++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 40f4a03d728f..d6ba13e1c540 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -293,5 +293,8 @@ extern void omap_reserve(void); struct omap_hwmod; extern int omap_dss_reset(struct omap_hwmod *); +/* SoC specific clock initializer */ +extern int (*omap_clk_init)(void); + #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 2c3fdd65387b..5c445ca1e271 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -54,6 +54,12 @@ #include "prm3xxx.h" #include "prm44xx.h" +/* + * omap_clk_init: points to a function that does the SoC-specific + * clock initializations + */ +int (*omap_clk_init)(void); + /* * The machine specific code may provide the extra mapping besides the * default mapping provided here. @@ -397,7 +403,7 @@ void __init omap2420_init_early(void) omap242x_clockdomains_init(); omap2420_hwmod_init(); omap_hwmod_init_postsetup(); - omap2420_clk_init(); + omap_clk_init = omap2420_clk_init; } void __init omap2420_init_late(void) @@ -427,7 +433,7 @@ void __init omap2430_init_early(void) omap243x_clockdomains_init(); omap2430_hwmod_init(); omap_hwmod_init_postsetup(); - omap2430_clk_init(); + omap_clk_init = omap2430_clk_init; } void __init omap2430_init_late(void) @@ -462,7 +468,7 @@ void __init omap3_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap3xxx_clk_init(); + omap_clk_init = omap3xxx_clk_init; } void __init omap3430_init_early(void) @@ -500,7 +506,7 @@ void __init ti81xx_init_early(void) omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); omap_hwmod_init_postsetup(); - omap3xxx_clk_init(); + omap_clk_init = omap3xxx_clk_init; } void __init omap3_init_late(void) @@ -568,7 +574,7 @@ void __init am33xx_init_early(void) am33xx_clockdomains_init(); am33xx_hwmod_init(); omap_hwmod_init_postsetup(); - am33xx_clk_init(); + omap_clk_init = am33xx_clk_init; } #endif @@ -593,7 +599,7 @@ void __init omap4430_init_early(void) omap44xx_clockdomains_init(); omap44xx_hwmod_init(); omap_hwmod_init_postsetup(); - omap4xxx_clk_init(); + omap_clk_init = omap4xxx_clk_init; } void __init omap4430_init_late(void) diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2bdd4cf17a8f..f62b509ed08d 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -547,6 +547,8 @@ static inline void __init realtime_counter_init(void) clksrc_nr, clksrc_src) \ void __init omap##name##_gptimer_timer_init(void) \ { \ + if (omap_clk_init) \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src); \ @@ -556,6 +558,8 @@ void __init omap##name##_gptimer_timer_init(void) \ clksrc_nr, clksrc_src) \ void __init omap##name##_sync32k_timer_init(void) \ { \ + if (omap_clk_init) \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ /* Enable the use of clocksource="gp_timer" kernel parameter */ \ -- cgit v1.2.3 From 2ab3a749eb14c96eaf453afe6e678c9c1dab1637 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 5 Mar 2013 09:06:58 +0100 Subject: gpio-ich: Fix value returned by ichx_gpio_request Per Documentation/gpio.txt, gpio_request callbacks should return 0 on success or a negative value on error. So it is not clear what was meant by letting ichx_gpio_request return 1 in some cases, nor how a caller would interpret it. Align the code with the comment above it and consider pins as available by default. Signed-off-by: Jean Delvare Cc: Grant Likely Acked-by: Peter Tyser Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f9dbd503fc40..de3c317bd3e2 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -214,7 +214,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr) * If it can't be trusted, assume that the pin can be used as a GPIO. */ if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f))) - return 1; + return 0; return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV; } -- cgit v1.2.3 From c2a2876e863356b092967ea62bebdb4dd663af80 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 26 Mar 2013 22:48:23 +0100 Subject: iommu/amd: Make sure dma_ops are set for hotplug devices There is a bug introduced with commit 27c2127 that causes devices which are hot unplugged and then hot-replugged to not have per-device dma_ops set. This causes these devices to not function correctly. Fixed with this patch. Cc: stable@vger.kernel.org Reported-by: Andreas Degert Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 98f555dafb55..b287ca33833d 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2466,18 +2466,16 @@ static int device_change_notifier(struct notifier_block *nb, /* allocate a protection domain if a device is added */ dma_domain = find_protection_domain(devid); - if (dma_domain) - goto out; - dma_domain = dma_ops_domain_alloc(); - if (!dma_domain) - goto out; - dma_domain->target_dev = devid; - - spin_lock_irqsave(&iommu_pd_list_lock, flags); - list_add_tail(&dma_domain->list, &iommu_pd_list); - spin_unlock_irqrestore(&iommu_pd_list_lock, flags); - - dev_data = get_dev_data(dev); + if (!dma_domain) { + dma_domain = dma_ops_domain_alloc(); + if (!dma_domain) + goto out; + dma_domain->target_dev = devid; + + spin_lock_irqsave(&iommu_pd_list_lock, flags); + list_add_tail(&dma_domain->list, &iommu_pd_list); + spin_unlock_irqrestore(&iommu_pd_list_lock, flags); + } dev->archdata.dma_ops = &amd_iommu_dma_ops; -- cgit v1.2.3 From d6b057b5dbba97e6ba13aace5270babd7c8b658c Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Wed, 20 Mar 2013 08:59:35 +0000 Subject: e1000: ethtool: Add missing dma_mapping_error-call in e1000_setup_desc_rings After dma_map_single, dma_mapping_error must be called. Signed-off-by: Christoph Paasch Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 43462d596a4e..ffd287196bf8 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -1053,6 +1053,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) txdr->buffer_info[i].dma = dma_map_single(&pdev->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&pdev->dev, txdr->buffer_info[i].dma)) { + ret_val = 4; + goto err_nomem; + } tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | @@ -1069,7 +1073,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) rxdr->buffer_info = kcalloc(rxdr->count, sizeof(struct e1000_buffer), GFP_KERNEL); if (!rxdr->buffer_info) { - ret_val = 4; + ret_val = 5; goto err_nomem; } @@ -1077,7 +1081,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, GFP_KERNEL); if (!rxdr->desc) { - ret_val = 5; + ret_val = 6; goto err_nomem; } memset(rxdr->desc, 0, rxdr->size); @@ -1101,7 +1105,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); if (!skb) { - ret_val = 6; + ret_val = 7; goto err_nomem; } skb_reserve(skb, NET_IP_ALIGN); @@ -1110,6 +1114,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) rxdr->buffer_info[i].dma = dma_map_single(&pdev->dev, skb->data, E1000_RXBUFFER_2048, DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, rxdr->buffer_info[i].dma)) { + ret_val = 8; + goto err_nomem; + } rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma); memset(skb->data, 0x00, skb->len); } -- cgit v1.2.3 From 065946c65a61943b4c609a0a1b1bac6742b3b593 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Wed, 20 Mar 2013 08:59:41 +0000 Subject: ixgb: Add missing dma_mapping_error-call in ixgb_alloc_rx_buffers After dma_map_single, dma_mapping_error must be called. It seems safe to not free the skb allocated in this function, as the skb can be reused later. Additionally this patch fixes one coding-style error. Signed-off-by: Christoph Paasch Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index ea4808373435..b5f94abe3cff 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -2159,6 +2159,10 @@ map_skb: skb->data, adapter->rx_buffer_len, DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, buffer_info->dma)) { + adapter->alloc_rx_buff_failed++; + break; + } rx_desc = IXGB_RX_DESC(*rx_ring, i); rx_desc->buff_addr = cpu_to_le64(buffer_info->dma); @@ -2168,7 +2172,8 @@ map_skb: rx_desc->status = 0; - if (++i == rx_ring->count) i = 0; + if (++i == rx_ring->count) + i = 0; buffer_info = &rx_ring->buffer_info[i]; } -- cgit v1.2.3 From 9afd9b7090225d78ef56423a2ff65354dc38f1b1 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 18 Mar 2013 11:45:05 +0100 Subject: gpio: stmpe: pass DT node to irqdomain The irq domain was implemented but the device tree node was not transmitted to irq_domain_add_simple(). Cc: stable@vger.kernel.org Signed-off-by: Gabriel Fernandez Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stmpe.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 770476a9da87..3ce5bc38ac31 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -307,11 +307,15 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { .xlate = irq_domain_xlate_twocell, }; -static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) +static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, + struct device_node *np) { - int base = stmpe_gpio->irq_base; + int base = 0; - stmpe_gpio->domain = irq_domain_add_simple(NULL, + if (!np) + base = stmpe_gpio->irq_base; + + stmpe_gpio->domain = irq_domain_add_simple(np, stmpe_gpio->chip.ngpio, base, &stmpe_gpio_irq_simple_ops, stmpe_gpio); if (!stmpe_gpio->domain) { @@ -346,6 +350,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; +#ifdef CONFIG_OF + stmpe_gpio->chip.of_node = np; +#endif stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; if (pdata) @@ -366,7 +373,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) goto out_free; if (irq >= 0) { - ret = stmpe_gpio_irq_init(stmpe_gpio); + ret = stmpe_gpio_irq_init(stmpe_gpio, np); if (ret) goto out_disable; -- cgit v1.2.3 From 37287fae7e4506fb0822523587c769783164cdd6 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Wed, 20 Mar 2013 08:59:46 +0000 Subject: e1000e: Add missing dma_mapping_error-call in e1000_alloc_jumbo_rx_buffers After dma_map_page, dma_mapping_error must be called. It seems safe to not free the skb/page allocated in this function, as the skb/page can be reused later. Signed-off-by: Christoph Paasch Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 948b86ffa4f0..7e615e2bf7e6 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -848,11 +848,16 @@ check_page: } } - if (!buffer_info->dma) + if (!buffer_info->dma) { buffer_info->dma = dma_map_page(&pdev->dev, buffer_info->page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, buffer_info->dma)) { + adapter->alloc_rx_buff_failed++; + break; + } + } rx_desc = E1000_RX_DESC_EXT(*rx_ring, i); rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma); -- cgit v1.2.3 From f901b6bc404b67d96eca739857c097e022727b71 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 27 Mar 2013 11:36:42 +0100 Subject: can: sja1000: fix define conflict on SH Thias patch fixes a define conflict between the SH architecture and the sja1000 driver: drivers/net/can/sja1000/sja1000.h:59:0: warning: "REG_SR" redefined [enabled by default] arch/sh/include/asm/ptrace_32.h:25:0: note: this is the location of the previous definition A SJA1000_ prefix is added to the offending sja1000 define only, to make a minimal patch suited for stable. A later patch will add a SJA1000_ prefix to all defines in sja1000.h. Cc: linux-stable Reported-by: Fengguang Wu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/plx_pci.c | 4 ++-- drivers/net/can/sja1000/sja1000.c | 6 +++--- drivers/net/can/sja1000/sja1000.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index a042cdc260dc..3c18d7d000ed 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -348,7 +348,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) */ if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) == REG_CR_BASICCAN_INITIAL && - (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) && + (priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_BASICCAN_INITIAL) && (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL)) flag = 1; @@ -360,7 +360,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) * See states on p. 23 of the Datasheet. */ if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL && - priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL && + priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_PELICAN_INITIAL && priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL) return flag; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index daf4013a8fc7..e4df307eaa90 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -92,7 +92,7 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val) */ spin_lock_irqsave(&priv->cmdreg_lock, flags); priv->write_reg(priv, REG_CMR, val); - priv->read_reg(priv, REG_SR); + priv->read_reg(priv, SJA1000_REG_SR); spin_unlock_irqrestore(&priv->cmdreg_lock, flags); } @@ -502,7 +502,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { n++; - status = priv->read_reg(priv, REG_SR); + status = priv->read_reg(priv, SJA1000_REG_SR); /* check for absent controller due to hw unplug */ if (status == 0xFF && sja1000_is_absent(priv)) return IRQ_NONE; @@ -530,7 +530,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) /* receive interrupt */ while (status & SR_RBS) { sja1000_rx(dev); - status = priv->read_reg(priv, REG_SR); + status = priv->read_reg(priv, SJA1000_REG_SR); /* check for absent controller */ if (status == 0xFF && sja1000_is_absent(priv)) return IRQ_NONE; diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index afa99847a510..aa48e053da27 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -56,7 +56,7 @@ /* SJA1000 registers - manual section 6.4 (Pelican Mode) */ #define REG_MOD 0x00 #define REG_CMR 0x01 -#define REG_SR 0x02 +#define SJA1000_REG_SR 0x02 #define REG_IR 0x03 #define REG_IER 0x04 #define REG_ALC 0x0B -- cgit v1.2.3 From f951b6587b94df2abb8c7a2425f7dcdb4fe647dc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Mar 2013 13:08:44 +0000 Subject: regmap: async: Add missing return Let's only write once... Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 3d2367501fd0..dd82acfbcf4e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1036,6 +1036,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, kfree(async->work_buf); kfree(async); } + + return ret; } trace_regmap_hw_write_start(map->dev, reg, -- cgit v1.2.3 From 4c43755506ececbe903585265aa8408e937620a1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 22 Mar 2013 18:53:57 +0100 Subject: HID: multitouch: fix touchpad buttons Commit "HID: multitouch: use the callback "report" instead..." breaks the buttons of touchpads following the HID multitouch specification. The buttons were emmitted through hid-input, but as now the events are generated only in hid-multitouch, the buttons are not emmitted anymore. The input_event() call is far much simpler than the hid-input one as many of the different tests do not apply to multitouch touchpads. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 7a1ebb867cf4..82e9211b3ca9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -621,6 +621,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass.quirks; + struct input_dev *input = field->hidinput->input; if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { @@ -670,13 +671,16 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, break; default: + if (usage->type) + input_event(input, usage->type, usage->code, + value); return; } if (usage->usage_index + 1 == field->report_count) { /* we only take into account the last report. */ if (usage->hid == td->last_slot_field) - mt_complete_slot(td, field->hidinput->input); + mt_complete_slot(td, input); if (field->index == td->last_field_index && td->num_received >= td->num_expected) -- cgit v1.2.3 From 9beb09f1cadf33145c307c504f844ae24686c872 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 4 Mar 2013 20:44:39 -0800 Subject: fbdev: sh_mobile_lcdc: fixup B side hsync adjust settings The lcdc B side horizon output is shifted if sh_mobile_lcdc_pan() was called. This patch fixup this issue. It is tested on R8A7740 Armadillo800eva HDMI output. Special thanks to Fukushima-san, and Sano-san Reported-by: Osamu Fukushima Signed-off-by: Hideyuki Sano Signed-off-by: Kuninori Morimoto Acked-by: Laurent Pinchart Signed-off-by: Simon Horman --- drivers/video/sh_mobile_lcdcfb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 63203acef812..0264704a52be 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -858,6 +858,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16) | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7); lcdc_write_chan(ch, LDHAJR, tmp); + lcdc_write_chan_mirror(ch, LDHAJR, tmp); } static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl) -- cgit v1.2.3 From 3fd33497f80aa528ded0db2851b48638635d5caa Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 27 Mar 2013 12:47:13 +0100 Subject: can: sja1000: limit PEAK PCAN-PC Card to HAS_IOPORT This patch limits the PEAK PCAN-PC Card driver to systems with ioports. Fixes a compile time breakage on SH: drivers/net/can/sja1000/peak_pcmcia.c:626:2: error: implicit declaration of function 'ioport_unmap' Reported-by: Fengguang Wu Cc: Paul Mundt Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index b39ca5b3ea7f..ff2ba86cd4a4 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -46,6 +46,7 @@ config CAN_EMS_PCI config CAN_PEAK_PCMCIA tristate "PEAK PCAN-PC Card" depends on PCMCIA + depends on HAS_IOPORT ---help--- This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels) from PEAK-System (http://www.peak-system.com). To compile this -- cgit v1.2.3 From 27b7c63a7c509d797c151e95a641e1d94d94bbd9 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Wed, 27 Mar 2013 15:04:55 +0200 Subject: drm/i915: Fix build failure ERROR: "__build_bug_on_failed" [drivers/gpu/drm/i915/i915.ko] undefined! Originally reported at http://www.gossamer-threads.com/lists/linux/kernel/1631803 FDO bug #62775 This needs to be backported to both 3.7 and 3.8 stable trees. Doesn't apply straight, but it's a quick change. Signed-off-by: Lauri Kasanen Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=62775 Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3b11ab0fbc96..9a48e1a2d417 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -57,7 +57,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args) if (eb == NULL) { int size = args->buffer_count; int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; - BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); + BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head)); while (count > 2*size) count >>= 1; eb = kzalloc(count*sizeof(struct hlist_head) + -- cgit v1.2.3 From 3151527ee007b73a0ebd296010f1c0454a919c7d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 15 Mar 2013 01:45:51 -0700 Subject: userns: Don't allow creation if the user is chrooted Guarantee that the policy of which files may be access that is established by setting the root directory will not be violated by user namespaces by verifying that the root directory points to the root of the mount namespace at the time of user namespace creation. Changing the root is a privileged operation, and as a matter of policy it serves to limit unprivileged processes to files below the current root directory. For reasons of simplicity and comprehensibility the privilege to change the root directory is gated solely on the CAP_SYS_CHROOT capability in the user namespace. Therefore when creating a user namespace we must ensure that the policy of which files may be access can not be violated by changing the root directory. Anyone who runs a processes in a chroot and would like to use user namespace can setup the same view of filesystems with a mount namespace instead. With this result that this is not a practical limitation for using user namespaces. Cc: stable@vger.kernel.org Acked-by: Serge Hallyn Reported-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 24 ++++++++++++++++++++++++ include/linux/fs_struct.h | 2 ++ kernel/user_namespace.c | 9 +++++++++ 3 files changed, 35 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 50ca17d3cb45..a3035223d421 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2732,6 +2732,30 @@ bool our_mnt(struct vfsmount *mnt) return check_mnt(real_mount(mnt)); } +bool current_chrooted(void) +{ + /* Does the current process have a non-standard root */ + struct path ns_root; + struct path fs_root; + bool chrooted; + + /* Find the namespace root */ + ns_root.mnt = ¤t->nsproxy->mnt_ns->root->mnt; + ns_root.dentry = ns_root.mnt->mnt_root; + path_get(&ns_root); + while (d_mountpoint(ns_root.dentry) && follow_down_one(&ns_root)) + ; + + get_fs_root(current->fs, &fs_root); + + chrooted = !path_equal(&fs_root, &ns_root); + + path_put(&fs_root); + path_put(&ns_root); + + return chrooted; +} + static void *mntns_get(struct task_struct *task) { struct mnt_namespace *ns = NULL; diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index 729eded4b24f..2b93a9a5a1e6 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -50,4 +50,6 @@ static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root, spin_unlock(&fs->lock); } +extern bool current_chrooted(void); + #endif /* _LINUX_FS_STRUCT_H */ diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index b14f4d342043..0f1e42884577 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -61,6 +61,15 @@ int create_user_ns(struct cred *new) kgid_t group = new->egid; int ret; + /* + * Verify that we can not violate the policy of which files + * may be accessed that is specified by the root directory, + * by verifing that the root directory is at the root of the + * mount namespace which allows all files to be accessed. + */ + if (current_chrooted()) + return -EPERM; + /* The creator needs a mapping in the parent user namespace * or else we won't be able to reasonably tell userspace who * created a user_namespace. -- cgit v1.2.3 From 90563b198e4c6674c63672fae1923da467215f45 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 22 Mar 2013 03:10:15 -0700 Subject: vfs: Add a mount flag to lock read only bind mounts When a read-only bind mount is copied from mount namespace in a higher privileged user namespace to a mount namespace in a lesser privileged user namespace, it should not be possible to remove the the read-only restriction. Add a MNT_LOCK_READONLY mount flag to indicate that a mount must remain read-only. CC: stable@vger.kernel.org Acked-by: Serge Hallyn Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 3 +++ include/linux/mount.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index a3035223d421..8505b5ece5de 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1713,6 +1713,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) if (readonly_request == __mnt_is_readonly(mnt)) return 0; + if (mnt->mnt_flags & MNT_LOCK_READONLY) + return -EPERM; + if (readonly_request) error = mnt_make_readonly(real_mount(mnt)); else diff --git a/include/linux/mount.h b/include/linux/mount.h index d7029f4a191a..73005f9957ea 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -47,6 +47,8 @@ struct mnt_namespace; #define MNT_INTERNAL 0x4000 +#define MNT_LOCK_READONLY 0x400000 + struct vfsmount { struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ -- cgit v1.2.3 From 132c94e31b8bca8ea921f9f96a57d684fa4ae0a9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 22 Mar 2013 04:08:05 -0700 Subject: vfs: Carefully propogate mounts across user namespaces As a matter of policy MNT_READONLY should not be changable if the original mounter had more privileges than creator of the mount namespace. Add the flag CL_UNPRIVILEGED to note when we are copying a mount from a mount namespace that requires more privileges to a mount namespace that requires fewer privileges. When the CL_UNPRIVILEGED flag is set cause clone_mnt to set MNT_NO_REMOUNT if any of the mnt flags that should never be changed are set. This protects both mount propagation and the initial creation of a less privileged mount namespace. Cc: stable@vger.kernel.org Acked-by: Serge Hallyn Reported-by: Andy Lutomirski Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 6 +++++- fs/pnode.c | 6 ++++++ fs/pnode.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index 8505b5ece5de..968d4c5eae03 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -798,6 +798,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, } mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; + /* Don't allow unprivileged users to change mount flags */ + if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) + mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; + atomic_inc(&sb->s_active); mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_root = dget(root); @@ -2342,7 +2346,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, /* First pass: copy the tree topology */ copy_flags = CL_COPY_ALL | CL_EXPIRE; if (user_ns != mnt_ns->user_ns) - copy_flags |= CL_SHARED_TO_SLAVE; + copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; new = copy_tree(old, old->mnt.mnt_root, copy_flags); if (IS_ERR(new)) { up_write(&namespace_sem); diff --git a/fs/pnode.c b/fs/pnode.c index 3e000a51ac0d..8b29d2164da6 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "internal.h" #include "pnode.h" @@ -220,6 +221,7 @@ static struct mount *get_source(struct mount *dest, int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, struct mount *source_mnt, struct list_head *tree_list) { + struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; struct mount *m, *child; int ret = 0; struct mount *prev_dest_mnt = dest_mnt; @@ -237,6 +239,10 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); + /* Notice when we are propagating across user namespaces */ + if (m->mnt_ns->user_ns != user_ns) + type |= CL_UNPRIVILEGED; + child = copy_tree(source, source->mnt.mnt_root, type); if (IS_ERR(child)) { ret = PTR_ERR(child); diff --git a/fs/pnode.h b/fs/pnode.h index 19b853a3445c..a0493d5ebfbf 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -23,6 +23,7 @@ #define CL_MAKE_SHARED 0x08 #define CL_PRIVATE 0x10 #define CL_SHARED_TO_SLAVE 0x20 +#define CL_UNPRIVILEGED 0x40 static inline void set_mnt_shared(struct mount *mnt) { -- cgit v1.2.3 From a636b702ed1805e988ad3d8ff8b52c060f8b341c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 21 Mar 2013 18:13:15 -0700 Subject: ipc: Restrict mounting the mqueue filesystem Only allow mounting the mqueue filesystem if the caller has CAP_SYS_ADMIN rights over the ipc namespace. The principle here is if you create or have capabilities over it you can mount it, otherwise you get to live with what other people have mounted. This information is not particularly sensitive and mqueue essentially only reports which posix messages queues exist. Still when creating a restricted environment for an application to live any extra information may be of use to someone with sufficient creativity. The historical if imperfect way this information has been restricted has been not to allow mounts and restricting this to ipc namespace creators maintains the spirit of the historical restriction. Cc: stable@vger.kernel.org Acked-by: Serge Hallyn Signed-off-by: "Eric W. Biederman" --- ipc/mqueue.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ipc/mqueue.c b/ipc/mqueue.c index e5c4f609f22c..c4ae32ec6c6b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -330,8 +330,16 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - if (!(flags & MS_KERNMOUNT)) - data = current->nsproxy->ipc_ns; + if (!(flags & MS_KERNMOUNT)) { + struct ipc_namespace *ns = current->nsproxy->ipc_ns; + /* Don't allow mounting unless the caller has CAP_SYS_ADMIN + * over the ipc namespace. + */ + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + data = ns; + } return mount_ns(fs_type, flags, data, mqueue_fill_super); } -- cgit v1.2.3 From 87a8ebd637dafc255070f503909a053cf0d98d3f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 24 Mar 2013 14:28:27 -0700 Subject: userns: Restrict when proc and sysfs can be mounted Only allow unprivileged mounts of proc and sysfs if they are already mounted when the user namespace is created. proc and sysfs are interesting because they have content that is per namespace, and so fresh mounts are needed when new namespaces are created while at the same time proc and sysfs have content that is shared between every instance. Respect the policy of who may see the shared content of proc and sysfs by only allowing new mounts if there was an existing mount at the time the user namespace was created. In practice there are only two interesting cases: proc and sysfs are mounted at their usual places, proc and sysfs are not mounted at all (some form of mount namespace jail). Cc: stable@vger.kernel.org Acked-by: Serge Hallyn Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 21 +++++++++++++++++++++ fs/proc/root.c | 4 ++++ fs/sysfs/mount.c | 4 ++++ include/linux/user_namespace.h | 4 ++++ kernel/user.c | 2 ++ kernel/user_namespace.c | 2 ++ 6 files changed, 37 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 968d4c5eae03..d581e45c0a9f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2763,6 +2763,27 @@ bool current_chrooted(void) return chrooted; } +void update_mnt_policy(struct user_namespace *userns) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + struct mount *mnt; + + down_read(&namespace_sem); + list_for_each_entry(mnt, &ns->list, mnt_list) { + switch (mnt->mnt.mnt_sb->s_magic) { + case SYSFS_MAGIC: + userns->may_mount_sysfs = true; + break; + case PROC_SUPER_MAGIC: + userns->may_mount_proc = true; + break; + } + if (userns->may_mount_sysfs && userns->may_mount_proc) + break; + } + up_read(&namespace_sem); +} + static void *mntns_get(struct task_struct *task) { struct mnt_namespace *ns = NULL; diff --git a/fs/proc/root.c b/fs/proc/root.c index c6e9fac26bac..9c7fab1d23f0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, } else { ns = task_active_pid_ns(current); options = data; + + if (!current_user_ns()->may_mount_proc) + return ERR_PTR(-EPERM); } sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8d924b5ec733..afd83273e6ce 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "sysfs.h" @@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, struct super_block *sb; int error; + if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs) + return ERR_PTR(-EPERM); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 4ce009324933..b6b215f13b45 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -26,6 +26,8 @@ struct user_namespace { kuid_t owner; kgid_t group; unsigned int proc_inum; + bool may_mount_sysfs; + bool may_mount_proc; }; extern struct user_namespace init_user_ns; @@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns) #endif +void update_mnt_policy(struct user_namespace *userns); + #endif /* _LINUX_USER_H */ diff --git a/kernel/user.c b/kernel/user.c index e81978e8c03b..8e635a18ab52 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -51,6 +51,8 @@ struct user_namespace init_user_ns = { .owner = GLOBAL_ROOT_UID, .group = GLOBAL_ROOT_GID, .proc_inum = PROC_USER_INIT_INO, + .may_mount_sysfs = true, + .may_mount_proc = true, }; EXPORT_SYMBOL_GPL(init_user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0f1e42884577..a54f26f82eb2 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -96,6 +96,8 @@ int create_user_ns(struct cred *new) set_cred_user_ns(new, ns); + update_mnt_policy(ns); + return 0; } -- cgit v1.2.3 From 54683441a92ebe20c5282465ea6f21e5e74d2974 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 27 Mar 2013 10:52:11 -0400 Subject: Revert "brcmsmac: support 4313iPA" This reverts commit b6fc28a158076ca2764edc9a6d1e1402f56e1c0c. This commit is reported to cause a regression in the support for some revisions of 4313 ePA devices. http://marc.info/?l=linux-wireless&m=136360340200943&w=2 Conflicts: drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c Reported-by: David Herrmann Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c | 369 ++++++++------------- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c | 64 ++-- 2 files changed, 162 insertions(+), 271 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 21a824232478..18d37645e2cd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,9 +1137,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, gain0_15 = ((biq1 & 0xf) << 12) | ((tia & 0xf) << 8) | ((lna2 & 0x3) << 6) | - ((lna2 & 0x3) << 4) | - ((lna1 & 0x3) << 2) | - ((lna1 & 0x3) << 0); + ((lna2 & + 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1157,8 +1156,6 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, } mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); - mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); - mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); } @@ -1331,43 +1328,6 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; } -static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, - u16 tia_gain, u16 lna2_gain) -{ - u32 i_thresh_l, q_thresh_l; - u32 i_thresh_h, q_thresh_h; - struct lcnphy_iq_est iq_est_h, iq_est_l; - - wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, - lna2_gain, 0); - - wlc_lcnphy_rx_gain_override_enable(pi, true); - wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); - udelay(500); - write_radio_reg(pi, RADIO_2064_REG112, 0); - if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) - return false; - - wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); - udelay(500); - write_radio_reg(pi, RADIO_2064_REG112, 0); - if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) - return false; - - i_thresh_l = (iq_est_l.i_pwr << 1); - i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; - - q_thresh_l = (iq_est_l.q_pwr << 1); - q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; - if ((iq_est_h.i_pwr > i_thresh_l) && - (iq_est_h.i_pwr < i_thresh_h) && - (iq_est_h.q_pwr > q_thresh_l) && - (iq_est_h.q_pwr < q_thresh_h)) - return true; - - return false; -} - static bool wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, const struct lcnphy_rx_iqcomp *iqcomp, @@ -1382,8 +1342,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, rfoverride3_old, rfoverride3val_old, rfoverride4_old, rfoverride4val_old, afectrlovr_old, afectrlovrval_old; - int tia_gain, lna2_gain, biq1_gain; - bool set_gain; + int tia_gain; + u32 received_power, rx_pwr_threshold; u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; u16 values_to_save[11]; s16 *ptr; @@ -1408,134 +1368,126 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, goto cal_done; } - WARN_ON(module != 1); - tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - - for (i = 0; i < 11; i++) - values_to_save[i] = - read_radio_reg(pi, rxiq_cal_rf_reg[i]); - Core1TxControl_old = read_phy_reg(pi, 0x631); - - or_phy_reg(pi, 0x631, 0x0015); - - RFOverride0_old = read_phy_reg(pi, 0x44c); - RFOverrideVal0_old = read_phy_reg(pi, 0x44d); - rfoverride2_old = read_phy_reg(pi, 0x4b0); - rfoverride2val_old = read_phy_reg(pi, 0x4b1); - rfoverride3_old = read_phy_reg(pi, 0x4f9); - rfoverride3val_old = read_phy_reg(pi, 0x4fa); - rfoverride4_old = read_phy_reg(pi, 0x938); - rfoverride4val_old = read_phy_reg(pi, 0x939); - afectrlovr_old = read_phy_reg(pi, 0x43b); - afectrlovrval_old = read_phy_reg(pi, 0x43c); - old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); - old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - - tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); - if (tx_gain_override_old) { - wlc_lcnphy_get_tx_gain(pi, &old_gains); - tx_gain_index_old = pi_lcn->lcnphy_current_index; - } - - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); + if (module == 1) { - mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + for (i = 0; i < 11; i++) + values_to_save[i] = + read_radio_reg(pi, rxiq_cal_rf_reg[i]); + Core1TxControl_old = read_phy_reg(pi, 0x631); + + or_phy_reg(pi, 0x631, 0x0015); + + RFOverride0_old = read_phy_reg(pi, 0x44c); + RFOverrideVal0_old = read_phy_reg(pi, 0x44d); + rfoverride2_old = read_phy_reg(pi, 0x4b0); + rfoverride2val_old = read_phy_reg(pi, 0x4b1); + rfoverride3_old = read_phy_reg(pi, 0x4f9); + rfoverride3val_old = read_phy_reg(pi, 0x4fa); + rfoverride4_old = read_phy_reg(pi, 0x938); + rfoverride4val_old = read_phy_reg(pi, 0x939); + afectrlovr_old = read_phy_reg(pi, 0x43b); + afectrlovrval_old = read_phy_reg(pi, 0x43c); + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); + + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) { + wlc_lcnphy_get_tx_gain(pi, &old_gains); + tx_gain_index_old = pi_lcn->lcnphy_current_index; + } - write_radio_reg(pi, RADIO_2064_REG116, 0x06); - write_radio_reg(pi, RADIO_2064_REG12C, 0x07); - write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); - write_radio_reg(pi, RADIO_2064_REG098, 0x03); - write_radio_reg(pi, RADIO_2064_REG00B, 0x7); - mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); - write_radio_reg(pi, RADIO_2064_REG01D, 0x01); - write_radio_reg(pi, RADIO_2064_REG114, 0x01); - write_radio_reg(pi, RADIO_2064_REG02E, 0x10); - write_radio_reg(pi, RADIO_2064_REG12A, 0x08); - - mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); - mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); - mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); - write_phy_reg(pi, 0x6da, 0xffff); - or_phy_reg(pi, 0x6db, 0x3); + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); - wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); - set_gain = false; - - lna2_gain = 3; - while ((lna2_gain >= 0) && !set_gain) { - tia_gain = 4; - - while ((tia_gain >= 0) && !set_gain) { - biq1_gain = 6; - - while ((biq1_gain >= 0) && !set_gain) { - set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, - (u16) - biq1_gain, - (u16) - tia_gain, - (u16) - lna2_gain); - biq1_gain -= 1; - } + write_radio_reg(pi, RADIO_2064_REG116, 0x06); + write_radio_reg(pi, RADIO_2064_REG12C, 0x07); + write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); + write_radio_reg(pi, RADIO_2064_REG098, 0x03); + write_radio_reg(pi, RADIO_2064_REG00B, 0x7); + mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); + write_radio_reg(pi, RADIO_2064_REG01D, 0x01); + write_radio_reg(pi, RADIO_2064_REG114, 0x01); + write_radio_reg(pi, RADIO_2064_REG02E, 0x10); + write_radio_reg(pi, RADIO_2064_REG12A, 0x08); + + mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); + + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + + wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + wlc_lcnphy_rx_gain_override_enable(pi, true); + + tia_gain = 8; + rx_pwr_threshold = 950; + while (tia_gain > 0) { tia_gain -= 1; + wlc_lcnphy_set_rx_gain_by_distribution(pi, + 0, 0, 2, 2, + (u16) + tia_gain, 1, 0); + udelay(500); + + received_power = + wlc_lcnphy_measure_digital_power(pi, 2000); + if (received_power < rx_pwr_threshold) + break; } - lna2_gain -= 1; - } + result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); - if (set_gain) - result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); - else - result = false; + wlc_lcnphy_stop_tx_tone(pi); - wlc_lcnphy_stop_tx_tone(pi); + write_phy_reg(pi, 0x631, Core1TxControl_old); - write_phy_reg(pi, 0x631, Core1TxControl_old); - - write_phy_reg(pi, 0x44c, RFOverrideVal0_old); - write_phy_reg(pi, 0x44d, RFOverrideVal0_old); - write_phy_reg(pi, 0x4b0, rfoverride2_old); - write_phy_reg(pi, 0x4b1, rfoverride2val_old); - write_phy_reg(pi, 0x4f9, rfoverride3_old); - write_phy_reg(pi, 0x4fa, rfoverride3val_old); - write_phy_reg(pi, 0x938, rfoverride4_old); - write_phy_reg(pi, 0x939, rfoverride4val_old); - write_phy_reg(pi, 0x43b, afectrlovr_old); - write_phy_reg(pi, 0x43c, afectrlovrval_old); - write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); - write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); + write_phy_reg(pi, 0x44c, RFOverrideVal0_old); + write_phy_reg(pi, 0x44d, RFOverrideVal0_old); + write_phy_reg(pi, 0x4b0, rfoverride2_old); + write_phy_reg(pi, 0x4b1, rfoverride2val_old); + write_phy_reg(pi, 0x4f9, rfoverride3_old); + write_phy_reg(pi, 0x4fa, rfoverride3val_old); + write_phy_reg(pi, 0x938, rfoverride4_old); + write_phy_reg(pi, 0x939, rfoverride4val_old); + write_phy_reg(pi, 0x43b, afectrlovr_old); + write_phy_reg(pi, 0x43c, afectrlovrval_old); + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); - wlc_lcnphy_clear_trsw_override(pi); + wlc_lcnphy_clear_trsw_override(pi); - mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); + mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); - for (i = 0; i < 11; i++) - write_radio_reg(pi, rxiq_cal_rf_reg[i], - values_to_save[i]); + for (i = 0; i < 11; i++) + write_radio_reg(pi, rxiq_cal_rf_reg[i], + values_to_save[i]); - if (tx_gain_override_old) - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); - else - wlc_lcnphy_disable_tx_gain_override(pi); + if (tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); + else + wlc_lcnphy_disable_tx_gain_override(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); - wlc_lcnphy_rx_gain_override_enable(pi, false); + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); + wlc_lcnphy_rx_gain_override_enable(pi, false); + } cal_done: kfree(ptr); @@ -1829,17 +1781,6 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) write_radio_reg(pi, RADIO_2064_REG038, 3); write_radio_reg(pi, RADIO_2064_REG091, 7); } - - if (!(pi->sh->boardflags & BFL_FEM)) { - u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc, - 0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0}; - - write_radio_reg(pi, RADIO_2064_REG02A, 0xf); - write_radio_reg(pi, RADIO_2064_REG091, 0x3); - write_radio_reg(pi, RADIO_2064_REG038, 0x3); - - write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); - } } static int @@ -2034,16 +1975,6 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) } else { mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); - mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); - mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); - mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); - mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); - mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); - mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); - mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); - mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); - mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); - mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4); } } else { mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2130,14 +2061,12 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); - mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0)); } static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) { struct phytbl_info tab; u32 rfseq, ind; - u8 tssi_sel; tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; @@ -2159,13 +2088,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); - if (pi->sh->boardflags & BFL_FEM) { - tssi_sel = 0x1; - wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); - } else { - tssi_sel = 0xe; - wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA); - } + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2201,10 +2124,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { - mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); + mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); } else { - mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1); mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); } @@ -2251,10 +2173,6 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); - mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); - mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); - mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); - wlc_lcnphy_pwrctrl_rssiparams(pi); } @@ -2873,8 +2791,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) read_radio_reg(pi, RADIO_2064_REG007) & 1; u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; - u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); - idleTssi = read_phy_reg(pi, 0x4ab); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -2892,12 +2808,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); wlc_lcnphy_tssi_setup(pi); - - mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); - mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); - - wlc_lcnphy_set_bbmult(pi, 0x0); - wlc_phy_do_dummy_tx(pi, true, OFF); idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) >> 0); @@ -2919,7 +2829,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); - wlc_lcnphy_set_bbmult(pi, SAVE_bbmult); wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); wlc_lcnphy_set_tx_gain(pi, &old_gains); wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); @@ -3133,11 +3042,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlc_lcnphy_write_table(pi, &tab); tab.tbl_offset++; } - mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); - mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); - mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); - mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); - mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2); mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); @@ -3939,6 +3843,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) target_gains.pad_gain = 21; target_gains.dac_gain = 0; wlc_lcnphy_set_tx_gain(pi, &target_gains); + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3949,7 +3854,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) lcnphy_recal ? LCNPHY_CAL_RECAL : LCNPHY_CAL_FULL), false); } else { - wlc_lcnphy_set_tx_pwr_by_index(pi, 16); wlc_lcnphy_tx_iqlo_soft_cal_full(pi); } @@ -4374,22 +4278,17 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, if (CHSPEC_IS5G(pi->radio_chanspec)) pa_gain = 0x70; else - pa_gain = 0x60; + pa_gain = 0x70; if (pi->sh->boardflags & BFL_FEM) pa_gain = 0x10; - tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; tab.tbl_len = 1; tab.tbl_ptr = &val; for (j = 0; j < 128; j++) { - if (pi->sh->boardflags & BFL_FEM) - gm_gain = gain_table[j].gm; - else - gm_gain = 15; - + gm_gain = gain_table[j].gm; val = (((u32) pa_gain << 24) | (gain_table[j].pad << 16) | (gain_table[j].pga << 8) | gm_gain); @@ -4600,10 +4499,7 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) write_phy_reg(pi, 0x4ea, 0x4688); - if (pi->sh->boardflags & BFL_FEM) - mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); - else - mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4614,13 +4510,6 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) wlc_lcnphy_rcal(pi); wlc_lcnphy_rc_cal(pi); - - if (!(pi->sh->boardflags & BFL_FEM)) { - write_radio_reg(pi, RADIO_2064_REG032, 0x6f); - write_radio_reg(pi, RADIO_2064_REG033, 0x19); - write_radio_reg(pi, RADIO_2064_REG039, 0xe); - } - } static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4650,20 +4539,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) wlc_lcnphy_write_table(pi, &tab); } - if (!(pi->sh->boardflags & BFL_FEM)) { - tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; - tab.tbl_width = 16; - tab.tbl_ptr = &val; - tab.tbl_len = 1; + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; - val = 150; - tab.tbl_offset = 0; - wlc_lcnphy_write_table(pi, &tab); + val = 114; + tab.tbl_offset = 0; + wlc_lcnphy_write_table(pi, &tab); - val = 220; - tab.tbl_offset = 1; - wlc_lcnphy_write_table(pi, &tab); - } + val = 130; + tab.tbl_offset = 1; + wlc_lcnphy_write_table(pi, &tab); + + val = 6; + tab.tbl_offset = 8; + wlc_lcnphy_write_table(pi, &tab); if (CHSPEC_IS2G(pi->radio_chanspec)) { if (pi->sh->boardflags & BFL_FEM) @@ -5055,7 +4946,6 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) wlc_lcnphy_load_tx_iir_filter(pi, true, 3); mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); - wlc_lcnphy_tssi_setup(pi); } void wlc_phy_detach_lcnphy(struct brcms_phy *pi) @@ -5094,7 +4984,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) return false; - if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { + if ((pi->sh->boardflags & BFL_FEM) && + (LCNREV_IS(pi->pubpi.phy_rev, 1))) { if (pi_lcn->lcnphy_tempsense_option == 3) { pi->hwpwrctrl = true; pi->hwpwrctrl_capable = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index b7e95acc2084..622c01ca72c5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = { }; static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { - 0x0009, 0x000a, - 0x0005, - 0x0006, 0x0009, - 0x000a, - 0x0005, 0x0006, - 0x0009, - 0x000a, 0x0005, - 0x0006, - 0x0009, 0x000a, - 0x0005, - 0x0006, 0x0009, - 0x000a, - 0x0005, 0x0006, - 0x0009, - 0x000a, 0x0005, - 0x0006, - 0x0009, 0x000a, - 0x0005, - 0x0006, 0x0009, - 0x000a, - 0x0005, 0x0006, - 0x0009, - 0x000a, 0x0005, - 0x0006, - 0x0009, 0x000a, - 0x0005, - 0x0006, 0x0009, - 0x000a, - 0x0005, 0x0006, - 0x0009, - 0x000a, 0x0005, - 0x0006, + 0x000a, 0x0009, + 0x0006, + 0x0005, 0x000a, + 0x0009, + 0x0006, 0x0005, + 0x000a, + 0x0009, 0x0006, + 0x0005, + 0x000a, 0x0009, + 0x0006, + 0x0005, 0x000a, + 0x0009, + 0x0006, 0x0005, + 0x000a, + 0x0009, 0x0006, + 0x0005, + 0x000a, 0x0009, + 0x0006, + 0x0005, 0x000a, + 0x0009, + 0x0006, 0x0005, + 0x000a, + 0x0009, 0x0006, + 0x0005, + 0x000a, 0x0009, + 0x0006, + 0x0005, 0x000a, + 0x0009, + 0x0006, 0x0005, + 0x000a, + 0x0009, 0x0006, + 0x0005, }; static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { -- cgit v1.2.3 From e67dd874e60529dbd2e8232babb1e23479ba2ffa Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 19 Mar 2013 07:52:48 +0100 Subject: b43: N-PHY: increase initial value of "mind" in RSSI calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're using "mind" variable to find the VCM that got the best polling results. For each VCM we calculte "currd" which is compared to the "mind". For PHY rev3+ "currd" gets values around 14k-40k. Looking for a value smaller than 40 makes no sense, so increase the initial value. This fixes a regression introduced in 3.4 by commit: e0c9a0219a8f542e3946fe972a68aacf8c3f906c (my BCM4322 performance dropped from 18,4Mb/s to 9,26Mb/s) Signed-off-by: Rafał Miłecki Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3c35382ee6c2..e014a7a8154d 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1615,7 +1615,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) } for (i = 0; i < 4; i += 2) { s32 curr; - s32 mind = 40; + s32 mind = 0x100000; s32 minpoll = 249; u8 minvcm = 0; if (2 * core != i) @@ -1799,7 +1799,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) } for (i = 0; i < 4; i++) { - s32 mind = 40; + s32 mind = 0x100000; u8 minvcm = 0; s32 minpoll = 249; s32 curr; -- cgit v1.2.3 From b251412db99ccd4495ce372fec7daee27bf06923 Mon Sep 17 00:00:00 2001 From: "Iestyn C. Elfick" Date: Wed, 20 Mar 2013 14:02:31 -0500 Subject: b43: A fix for DMA transmission sequence errors Intermittently, b43 will report "Out of order TX status report on DMA ring". When this happens, the driver must be reset before communication can resume. The cause of the problem is believed to be an error in the closed-source firmware; however, all versions of the firmware are affected. This change uses the observation that the expected status is always 2 less than the observed value, and supplies a fake status report to skip one header/data pair. Not all devices suffer from this problem, but it can occur several times per second under heavy load. As each occurence kills the unmodified driver, this patch makes if possible for the affected devices to function. The patch logs only the first instance of the reset operation to prevent spamming the logs. Tested-by: Chris Vine Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 65 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 38bc5a7997ff..122146943bf2 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1487,8 +1487,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_dma_ops *ops; struct b43_dmaring *ring; struct b43_dmadesc_meta *meta; + static const struct b43_txstatus fake; /* filled with 0 */ + const struct b43_txstatus *txstat; int slot, firstused; bool frame_succeed; + int skip; + static u8 err_out1, err_out2; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) @@ -1501,13 +1505,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, firstused = ring->current_slot - ring->used_slots + 1; if (firstused < 0) firstused = ring->nr_slots + firstused; + + skip = 0; if (unlikely(slot != firstused)) { /* This possibly is a firmware bug and will result in - * malfunction, memory leaks and/or stall of DMA functionality. */ - b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " - "Expected %d, but got %d\n", - ring->index, firstused, slot); - return; + * malfunction, memory leaks and/or stall of DMA functionality. + */ + if (slot == next_slot(ring, next_slot(ring, firstused))) { + /* If a single header/data pair was missed, skip over + * the first two slots in an attempt to recover. + */ + slot = firstused; + skip = 2; + if (!err_out1) { + /* Report the error once. */ + b43dbg(dev->wl, + "Skip on DMA ring %d slot %d.\n", + ring->index, slot); + err_out1 = 1; + } + } else { + /* More than a single header/data pair were missed. + * Report this error once. + */ + if (!err_out2) + b43dbg(dev->wl, + "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", + ring->index, firstused, slot); + err_out2 = 1; + return; + } } ops = ring->ops; @@ -1522,11 +1549,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, slot, firstused, ring->index); break; } + if (meta->skb) { struct b43_private_tx_info *priv_info = - b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); + b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); - unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); kfree(priv_info->bouncebuffer); priv_info->bouncebuffer = NULL; } else { @@ -1538,8 +1567,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, struct ieee80211_tx_info *info; if (unlikely(!meta->skb)) { - /* This is a scatter-gather fragment of a frame, so - * the skb pointer must not be NULL. */ + /* This is a scatter-gather fragment of a frame, + * so the skb pointer must not be NULL. + */ b43dbg(dev->wl, "TX status unexpected NULL skb " "at slot %d (first=%d) on ring %d\n", slot, firstused, ring->index); @@ -1550,9 +1580,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, /* * Call back to inform the ieee80211 subsystem about - * the status of the transmission. + * the status of the transmission. When skipping over + * a missed TX status report, use a status structure + * filled with zeros to indicate that the frame was not + * sent (frame_count 0) and not acknowledged */ - frame_succeed = b43_fill_txstatus_report(dev, info, status); + if (unlikely(skip)) + txstat = &fake; + else + txstat = status; + + frame_succeed = b43_fill_txstatus_report(dev, info, + txstat); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; @@ -1580,12 +1619,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, /* Everything unmapped and free'd. So it's not used anymore. */ ring->used_slots--; - if (meta->is_last_fragment) { + if (meta->is_last_fragment && !skip) { /* This is the last scatter-gather * fragment of the frame. We are done. */ break; } slot = next_slot(ring, slot); + if (skip > 0) + --skip; } if (ring->stopped) { B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); -- cgit v1.2.3 From 7fc0357479eeff4ca808c4d8c09bc7631f576b8d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 25 Mar 2013 11:27:46 -0700 Subject: ath9k: avoid queueing hw check work when suspended The following issue was reported. WARNING: at net/mac80211/util.c:599 ieee80211_can_queue_work.isra.7+0x32/0x40 [mac80211]() Hardware name: iMac12,1 queueing ieee80211 work while going to suspend Pid: 0, comm: swapper/0 Tainted: PF O 3.8.2-206.fc18.x86_64 #1 Call Trace: Mar 16 09:39:17 Parags-iMac kernel: [ 3993.642992] [] warn_slowpath_common+0x7f/0xc0 [] ? ath_start_rx_poll+0x70/0x70 [ath9k] ] warn_slowpath_fmt+0x46/0x50 [] ieee80211_can_queue_work.isra.7+0x32/0x40 Fix this by avoiding to queue the work if our device has already been marked as suspended or stopped. Reported-by: Parag Warudkar Tested-by: Parag Warudkar Cc: stable@vger.kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/link.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 39c84ecf6a42..7fdac6c7b3ea 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; - ieee80211_queue_work(sc->hw, &sc->hw_check_work); + if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) + ieee80211_queue_work(sc->hw, &sc->hw_check_work); } /* -- cgit v1.2.3 From ace5af39866da7d45f43774150dace19a73716d6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 26 Mar 2013 17:35:23 +0000 Subject: iwlegacy: 4965-rs: avoid null pointer dereference error il4965_rs_initialize_lq checks to see if sta is null, however, before that check il4965_rs_use_green dereferences sta when intializing use_green. Avoid a potential null pointer dereference error by only calling il4965_rs_use_green after we are sure sta is not null. Smatch analysis: drivers/net/wireless/iwlegacy/4965-rs.c:2160 il4965_rs_initialize_lq() warn: variable dereferenced before check 'sta' (see line 2155) Signed-off-by: Colin Ian King Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/4965-rs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index e8324b5e5bfe..6c7493c2d698 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf, int rate_idx; int i; u32 rate; - u8 use_green = il4965_rs_use_green(il, sta); + u8 use_green; u8 active_tbl = 0; u8 valid_tx_ant; struct il_station_priv *sta_priv; @@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf, if (!sta || !lq_sta) return; + use_green = il4965_rs_use_green(il, sta); sta_priv = (void *)sta->drv_priv; i = lq_sta->last_txrate_idx; -- cgit v1.2.3 From 8ac3e99e693cb876776646c07f0a954a17ee3017 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 26 Mar 2013 14:40:51 -0500 Subject: libertas: drop maintainership Would be better maintained by somebody who actualy has time for it. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 95616582c728..92efc747e726 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5043,9 +5043,8 @@ S: Maintained F: drivers/net/ethernet/marvell/sk* MARVELL LIBERTAS WIRELESS DRIVER -M: Dan Williams L: libertas-dev@lists.infradead.org -S: Maintained +S: Orphan F: drivers/net/wireless/libertas/ MARVELL MV643XX ETHERNET DRIVER -- cgit v1.2.3 From 2e1253d640eb7f8707d2591c93097c1e9f9c71d5 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 27 Mar 2013 08:37:08 +0100 Subject: b43: N-PHY: use more bits for offset in RSSI calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calculating "offset" for final RSSI calibration we're using numbers bigger than s8 can hold. We have for example: offset[j] = 232 - poll_results[j]; formula. If poll_results[j] is small enough (it usually is) we treat number's bit as a sign bit. For example 232 - 1 becomes: 0xE8 - 0x1 = 0xE7, which is not 231 but -25. This code was introduced in e0c9a0219a8f542e3946fe972a68aacf8c3f906c and caused stability regression on some cards, for ex. BCM4322. Signed-off-by: Rafał Miłecki Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e014a7a8154d..e8486c1e091a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1564,7 +1564,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) u16 clip_off[2] = { 0xFFFF, 0xFFFF }; u8 vcm_final = 0; - s8 offset[4]; + s32 offset[4]; s32 results[8][4] = { }; s32 results_min[4] = { }; s32 poll_results[4] = { }; @@ -1732,7 +1732,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) u8 regs_save_radio[2]; u16 regs_save_phy[2]; - s8 offset[4]; + s32 offset[4]; u8 core; u8 rail; -- cgit v1.2.3 From 658e6101d045ae0bc97d31f5d6a5ea117a86c92a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 25 Mar 2013 15:50:22 +0000 Subject: ASoC: wm5102: Implement OSR support Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b7a3fdceec7f..a1ff43c8b479 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -612,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const char *wm5102_osr_text[] = { + "Low power", "Normal", "High performance", +}; + +static const unsigned int wm5102_osr_val[] = { + 0x0, 0x3, 0x5, +}; + +static const struct soc_enum wm5102_hpout_osr[] = { + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, + ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, + ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), + SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, + ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, + wm5102_osr_text, wm5102_osr_val), +}; + #define WM5102_NG_SRC(name, base) \ SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ @@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), +SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, + ARIZONA_OUT4_OSR_SHIFT, 1, 0), SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, ARIZONA_OUT5_OSR_SHIFT, 1, 0), @@ -790,6 +812,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]), +SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]), +SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]), + SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), -- cgit v1.2.3 From c8fa48d3722a9be89acf3486444e87583379c97c Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Tue, 26 Mar 2013 18:36:01 +0100 Subject: usb: Fix compile error by selecting USB_OTG_UTILS The current lpc32xx_defconfig breaks like this, caused by recent phy restructuring: LD init/built-in.o drivers/built-in.o: In function `usb_hcd_nxp_probe': drivers/usb/host/ohci-nxp.c:224: undefined reference to `isp1301_get_client' drivers/built-in.o: In function `lpc32xx_udc_probe': drivers/usb/gadget/lpc32xx_udc.c:3104: undefined reference to `isp1301_get_client' distcc[27867] ERROR: compile (null) on localhost failed make: *** [vmlinux] Error 1 Caused by 1c2088812f095df77f4b3224b65db79d7111a300 (usb: Makefile: fix drivers/usb/phy/ Makefile entry) This patch fixes this by selecting USB_OTG_UTILS in Kconfig which causes the phy driver to be built again. Signed-off-by: Roland Stigge Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/phy/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5a0c541daf89..c7525b1cad74 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -145,6 +145,7 @@ config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" depends on ARCH_LPC32XX select USB_ISP1301 + select USB_OTG_UTILS help This option selects the USB device controller in the LPC32xx SoC. diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 65217a590068..90549382eba5 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -38,6 +38,7 @@ config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET depends on I2C + select USB_OTG_UTILS help Say Y here to add support for the NXP ISP1301 USB transceiver driver. This chip is typically used as USB transceiver for USB host, gadget -- cgit v1.2.3 From 76fc253723add627cf28c09c79fb67e71f9e4782 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 22 Mar 2013 10:15:47 -0400 Subject: xen/acpi-stub: Disable it b/c the acpi_processor_add is no longer called. With the Xen ACPI stub code (CONFIG_XEN_STUB=y) enabled, the power C and P states are no longer uploaded to the hypervisor. The reason is that the Xen CPU hotplug code: xen-acpi-cpuhotplug.c and the xen-acpi-stub.c register themselves as the "processor" type object. That means the generic processor (processor_driver.c) stops working and it does not call (acpi_processor_add) which populates the per_cpu(processors, pr->id) = pr; structure. The 'pr' is gathered from the acpi_processor_get_info function which does the job of finding the C-states and figuring out PBLK address. The 'processors->pr' is then later used by xen-acpi-processor.c (the one that uploads C and P states to the hypervisor). Since it is NULL, we end skip the gathering of _PSD, _PSS, _PCT, etc and never upload the power management data. The end result is that enabling the CONFIG_XEN_STUB in the build means that xen-acpi-processor is not working anymore. This temporary patch fixes it by marking the XEN_STUB driver as BROKEN until this can be properly fixed. CC: jinsong.liu@intel.com Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 5a32232cf7c1..67af155cf602 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -182,7 +182,7 @@ config XEN_PRIVCMD config XEN_STUB bool "Xen stub drivers" - depends on XEN && X86_64 + depends on XEN && X86_64 && BROKEN default n help Allow kernel to install stub drivers, to reserve space for Xen drivers, -- cgit v1.2.3 From d3eb2c89e7ba996e8781b22a6e7d0a895ef55630 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 22 Mar 2013 10:34:28 -0400 Subject: xen/mmu: Move the setting of pvops.write_cr3 to later phase in bootup. We move the setting of write_cr3 from the early bootup variant (see git commit 0cc9129d75ef8993702d97ab0e49542c15ac6ab9 "x86-64, xen, mmu: Provide an early version of write_cr3.") to a more appropiate location. This new location sets all of the other non-early variants of pvops calls - and most importantly is before the alternative_asm mechanism kicks in. Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/xen/mmu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index e8e34938c57d..6afbb2ca9a0a 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1467,8 +1467,6 @@ static void __init xen_write_cr3_init(unsigned long cr3) __xen_write_cr3(true, cr3); xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */ - - pv_mmu_ops.write_cr3 = &xen_write_cr3; } #endif @@ -2122,6 +2120,7 @@ static void __init xen_post_allocator_init(void) #endif #ifdef CONFIG_X86_64 + pv_mmu_ops.write_cr3 = &xen_write_cr3; SetPagePinned(virt_to_page(level3_user_vsyscall)); #endif xen_mark_init_mm_pinned(); -- cgit v1.2.3 From c26377e62f4e6bfb4d99ef88526047209701a83f Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 25 Mar 2013 14:11:19 +0000 Subject: xen/events: avoid race with raising an event in unmask_evtchn() In unmask_evtchn(), when the mask bit is cleared after testing for pending and the event becomes pending between the test and clear, then the upcall will not become pending and the event may be lost or delayed. Avoid this by always clearing the mask bit before checking for pending. If a hypercall is needed, remask the event as EVTCHNOP_unmask will only retrigger pending events if they were masked. This fixes a regression introduced in 3.7 by b5e579232d635b79a3da052964cb357ccda8d9ea (xen/events: fix unmask_evtchn for PV on HVM guests) which reordered the clear mask and check pending operations. Changes in v2: - set mask before hypercall. Cc: stable@vger.kernel.org Acked-by: Stefano Stabellini Signed-off-by: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d17aa41a9041..aa85881d17b2 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -403,11 +403,23 @@ static void unmask_evtchn(int port) if (unlikely((cpu != cpu_from_evtchn(port)))) do_hypercall = 1; - else + else { + /* + * Need to clear the mask before checking pending to + * avoid a race with an event becoming pending. + * + * EVTCHNOP_unmask will only trigger an upcall if the + * mask bit was set, so if a hypercall is needed + * remask the event. + */ + sync_clear_bit(port, BM(&s->evtchn_mask[0])); evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); - if (unlikely(evtchn_pending && xen_hvm_domain())) - do_hypercall = 1; + if (unlikely(evtchn_pending && xen_hvm_domain())) { + sync_set_bit(port, BM(&s->evtchn_mask[0])); + do_hypercall = 1; + } + } /* Slow path (hypercall) if this is a non-local port or if this is * an hvm domain and an event is pending (hvm domains don't have @@ -418,8 +430,6 @@ static void unmask_evtchn(int port) } else { struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); - sync_clear_bit(port, BM(&s->evtchn_mask[0])); - /* * The following is basically the equivalent of * 'hw_resend_irq'. Just like a real IO-APIC we 'lose -- cgit v1.2.3 From 3e84f48edfd33b2e209a117c11fb9ce637cc9b67 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Mar 2013 15:20:30 +0000 Subject: vfs/splice: Fix missed checks in new __kernel_write() helper Commit 06ae43f34bcc ("Don't bother with redoing rw_verify_area() from default_file_splice_from()") lost the checks to test existence of the write/aio_write methods. My apologies ;-/ Eventually, we want that in fs/splice.c side of things (no point repeating it for every buffer, after all), but for now this is the obvious minimal fix. Reported-by: Dave Jones Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/read_write.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/read_write.c b/fs/read_write.c index f7b5a23b804b..e6ddc8dceb96 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -424,6 +424,9 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t const char __user *p; ssize_t ret; + if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) + return -EINVAL; + old_fs = get_fs(); set_fs(get_ds()); p = (__force const char __user *)buf; -- cgit v1.2.3 From 5389090b59f7f72a30e25f5fd1fc560340543970 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 27 Mar 2013 03:57:10 +0000 Subject: netfilter: nf_conntrack: fix error return code Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in function nf_conntrack_standalone_init(). Signed-off-by: Wei Yongjun Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_standalone.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 6bcce401fd1c..fedee3943661 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -568,6 +568,7 @@ static int __init nf_conntrack_standalone_init(void) register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); if (!nf_ct_netfilter_header) { pr_err("nf_conntrack: can't register to sysctl.\n"); + ret = -ENOMEM; goto out_sysctl; } #endif -- cgit v1.2.3 From 14109a59caf93e6eae726a34bf2f0897508ec8c1 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 26 Mar 2013 16:12:03 +0000 Subject: enet: fec: fix fail resume from suspend state Without this patch 1. boot with nfs (no_console_suspend) 2. echo mem >/sys/power/state 3. wakeup by wakesource 4. print "eth0: tx queue full" This fix above problem by reinit bd queue at restart function Signed-off-by: Frank Li Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.c | 82 ++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 911d0253dbb2..f292c3aa423f 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -345,6 +345,53 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } +/* Init RX & TX buffer descriptors + */ +static void fec_enet_bd_init(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + struct bufdesc *bdp; + unsigned int i; + + /* Initialize the receive buffer descriptors. */ + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + + /* Initialize the BD for every fragment in the page. */ + if (bdp->cbd_bufaddr) + bdp->cbd_sc = BD_ENET_RX_EMPTY; + else + bdp->cbd_sc = 0; + bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + } + + /* Set the last buffer to wrap */ + bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp->cbd_sc |= BD_SC_WRAP; + + fep->cur_rx = fep->rx_bd_base; + + /* ...and the same for transmit */ + bdp = fep->tx_bd_base; + fep->cur_tx = bdp; + for (i = 0; i < TX_RING_SIZE; i++) { + + /* Initialize the BD for every fragment in the page. */ + bdp->cbd_sc = 0; + if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) { + dev_kfree_skb_any(fep->tx_skbuff[i]); + fep->tx_skbuff[i] = NULL; + } + bdp->cbd_bufaddr = 0; + bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + } + + /* Set the last buffer to wrap */ + bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp->cbd_sc |= BD_SC_WRAP; + fep->dirty_tx = bdp; +} + /* This function is called to start or restart the FEC during a link * change. This only happens when switching between half and full * duplex. @@ -388,6 +435,8 @@ fec_restart(struct net_device *ndev, int duplex) /* Set maximum receive buffer size. */ writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); + fec_enet_bd_init(ndev); + /* Set receive and transmit descriptor base. */ writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); if (fep->bufdesc_ex) @@ -397,7 +446,6 @@ fec_restart(struct net_device *ndev, int duplex) writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); - fep->cur_rx = fep->rx_bd_base; for (i = 0; i <= TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i]) { @@ -1597,8 +1645,6 @@ static int fec_enet_init(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); struct bufdesc *cbd_base; - struct bufdesc *bdp; - unsigned int i; /* Allocate memory for buffer descriptors. */ cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, @@ -1608,6 +1654,7 @@ static int fec_enet_init(struct net_device *ndev) return -ENOMEM; } + memset(cbd_base, 0, PAGE_SIZE); spin_lock_init(&fep->hw_lock); fep->netdev = ndev; @@ -1631,35 +1678,6 @@ static int fec_enet_init(struct net_device *ndev) writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); - /* Initialize the receive buffer descriptors. */ - bdp = fep->rx_bd_base; - for (i = 0; i < RX_RING_SIZE; i++) { - - /* Initialize the BD for every fragment in the page. */ - bdp->cbd_sc = 0; - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); - } - - /* Set the last buffer to wrap */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); - bdp->cbd_sc |= BD_SC_WRAP; - - /* ...and the same for transmit */ - bdp = fep->tx_bd_base; - fep->cur_tx = bdp; - for (i = 0; i < TX_RING_SIZE; i++) { - - /* Initialize the BD for every fragment in the page. */ - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); - } - - /* Set the last buffer to wrap */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); - bdp->cbd_sc |= BD_SC_WRAP; - fep->dirty_tx = bdp; - fec_restart(ndev, 0); return 0; -- cgit v1.2.3 From fcca143d696092110ae1e361866576804fe887f3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 27 Mar 2013 03:22:45 +0000 Subject: rtnetlink: fix error return code in rtnl_link_fill() Fix to return a negative error code from the error handling case instead of 0(possible overwrite to 0 by ops->fill_xstats call), as returned elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5fb8d7e47294..b65441da74ab 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -496,8 +496,10 @@ static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) } if (ops->fill_info) { data = nla_nest_start(skb, IFLA_INFO_DATA); - if (data == NULL) + if (data == NULL) { + err = -EMSGSIZE; goto err_cancel_link; + } err = ops->fill_info(skb, dev); if (err < 0) goto err_cancel_data; -- cgit v1.2.3 From b56d6b3fca6d1214dbc9c5655f26e5d4ec04afc8 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Wed, 27 Mar 2013 04:41:59 +0000 Subject: drivers: net: ethernet: cpsw: use netif_wake_queue() while restarting tx queue To restart tx queue use netif_wake_queue() intead of netif_start_queue() so that net schedule will restart transmission immediately which will increase network performance while doing huge data transfers. Reported-by: Dan Franke Suggested-by: Sriramakrishnan A G Signed-off-by: Mugunthan V N Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index df32a090d08e..80cad06e5eb2 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -436,7 +436,7 @@ void cpsw_tx_handler(void *token, int len, int status) * queue is stopped then start the queue as we have free desc for tx */ if (unlikely(netif_queue_stopped(ndev))) - netif_start_queue(ndev); + netif_wake_queue(ndev); cpts_tx_timestamp(priv->cpts, skb); priv->stats.tx_packets++; priv->stats.tx_bytes += len; -- cgit v1.2.3 From 7e51cde276ca820d526c6c21cf8147df595a36bf Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Wed, 27 Mar 2013 04:42:00 +0000 Subject: drivers: net: ethernet: davinci_emac: use netif_wake_queue() while restarting tx queue To restart tx queue use netif_wake_queue() intead of netif_start_queue() so that net schedule will restart transmission immediately which will increase network performance while doing huge data transfers. Reported-by: Dan Franke Suggested-by: Sriramakrishnan A G Signed-off-by: Mugunthan V N Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ae1b77aa199f..72300bc9e378 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1053,7 +1053,7 @@ static void emac_tx_handler(void *token, int len, int status) * queue is stopped then start the queue as we have free desc for tx */ if (unlikely(netif_queue_stopped(ndev))) - netif_start_queue(ndev); + netif_wake_queue(ndev); ndev->stats.tx_packets++; ndev->stats.tx_bytes += len; dev_kfree_skb_any(skb); -- cgit v1.2.3 From ea872d7712528ad991bdabb63515bc00ee10993e Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Wed, 27 Mar 2013 05:41:59 +0000 Subject: sch: add missing u64 in psched_ratecfg_precompute() It seems that commit commit 292f1c7ff6cc10516076ceeea45ed11833bb71c7 Author: Jiri Pirko Date: Tue Feb 12 00:12:03 2013 +0000 sch: make htb_rate_cfg and functions around that generic adds little regression. Before: # tc qdisc add dev eth0 root handle 1: htb default ffff # tc class add dev eth0 classid 1:ffff htb rate 5Gbit # tc -s class show dev eth0 class htb 1:ffff root prio 0 rate 5000Mbit ceil 5000Mbit burst 625b cburst 625b Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) rate 0bit 0pps backlog 0b 0p requeues 0 lended: 0 borrowed: 0 giants: 0 tokens: 31 ctokens: 31 After: # tc qdisc add dev eth0 root handle 1: htb default ffff # tc class add dev eth0 classid 1:ffff htb rate 5Gbit # tc -s class show dev eth0 class htb 1:ffff root prio 0 rate 1544Mbit ceil 1544Mbit burst 625b cburst 625b Sent 5073 bytes 41 pkt (dropped 0, overlimits 0 requeues 0) rate 1976bit 2pps backlog 0b 0p requeues 0 lended: 41 borrowed: 0 giants: 0 tokens: 1802 ctokens: 1802 This probably due to lost u64 cast of rate parameter in psched_ratecfg_precompute() (net/sched/sch_generic.c). Signed-off-by: Sergey Popovich Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index ffad48109a22..eac7e0ee23c1 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -904,7 +904,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r, u32 rate) u64 mult; int shift; - r->rate_bps = rate << 3; + r->rate_bps = (u64)rate << 3; r->shift = 0; r->mult = 1; /* -- cgit v1.2.3 From 715230a44310a8cf66fbfb5a46f9a62a9b2de424 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 27 Mar 2013 06:40:50 +0000 Subject: tg3: fix length overflow in VPD firmware parsing Commit 184b89044fb6e2a74611dafa69b1dce0d98612c6 ("tg3: Use VPD fw version when present") introduced VPD parsing that contained a potential length overflow. Limit the hardware's reported firmware string length (max 255 bytes) to stay inside the driver's firmware string length (32 bytes). On overflow, truncate the formatted firmware string instead of potentially overwriting portions of the tg3 struct. http://cansecwest.com/slides/2013/PrivateCore%20CSW%202013.pdf Signed-off-by: Kees Cook Reported-by: Oded Horovitz Reported-by: Brad Spengler Cc: stable@vger.kernel.org Cc: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 67d2663b3974..17a972734ba7 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14604,8 +14604,11 @@ static void tg3_read_vpd(struct tg3 *tp) if (j + len > block_end) goto partno; - memcpy(tp->fw_ver, &vpd_data[j], len); - strncat(tp->fw_ver, " bc ", vpdlen - len - 1); + if (len >= sizeof(tp->fw_ver)) + len = sizeof(tp->fw_ver) - 1; + memset(tp->fw_ver, 0, sizeof(tp->fw_ver)); + snprintf(tp->fw_ver, sizeof(tp->fw_ver), "%.*s bc ", len, + &vpd_data[j]); } partno: -- cgit v1.2.3 From 24f11a5cf538a8fcc10d61f457e9a2094fb965b4 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 27 Mar 2013 06:54:00 +0000 Subject: line up comment for ndo_bridge_getlink Signed-off-by: Dmitry Kravkov Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b3d00fa4b314..8bfa95600e48 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -895,7 +895,7 @@ struct netdev_fcoe_hbainfo { * * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh) * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq, - * struct net_device *dev) + * struct net_device *dev, u32 filter_mask) * * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); * Called to change device carrier. Soft-devices (like dummy, team, etc) -- cgit v1.2.3 From e73081d9afd4b5fe285d2a585a73d9c6f73ab0dd Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 26 Mar 2013 10:26:15 +0000 Subject: ARM: ux500: Apply the TCPM and TCDM locations and sizes to dbx5x0 DT This fixes a regression introduced by commit: 05ec260 mfd:db8500-prcmu: update resource passing All DBx5x0 based SoCs have access to two Tightly Coupled Memory (TCM) locations based on the PRCMU itself. One area from program memory (TCPM) and one for data memory (TCDM). The PRCMU needs to know where these are in order to function correctly. However, these are currently passed though platform device resources, which can only be obtained if Device Tree booting isn't in use. Thus we must also support them in DT by supplying them through the PRCMU node. Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/boot/dts/dbx5x0.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi index 9de93096601a..aaa63d0a8096 100644 --- a/arch/arm/boot/dts/dbx5x0.dtsi +++ b/arch/arm/boot/dts/dbx5x0.dtsi @@ -191,8 +191,8 @@ prcmu: prcmu@80157000 { compatible = "stericsson,db8500-prcmu"; - reg = <0x80157000 0x1000>; - reg-names = "prcmu"; + reg = <0x80157000 0x1000>, <0x801b0000 0x8000>, <0x801b8000 0x1000>; + reg-names = "prcmu", "prcmu-tcpm", "prcmu-tcdm"; interrupts = <0 47 0x4>; #address-cells = <1>; #size-cells = <1>; -- cgit v1.2.3 From 26135256d3e7d4d12c6268623edc1740888c041f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 27 Mar 2013 10:47:38 +0000 Subject: ARM: ux500: Stop passing ios_handler() as an MMCI power controlling call-back This fixes a regression introduced during the v3.9 merge window. Now MMCI on/off functionality is using the regulator framework from the MMCI driver, if we provide the ios_handler call-back we essentially duplicate functionality, which causes a large mess and lots of booting issues. Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/board-mop500-sdi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c index 051b62c27102..7f2cb6c5e2c1 100644 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ b/arch/arm/mach-ux500/board-mop500-sdi.c @@ -81,7 +81,6 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { #endif struct mmci_platform_data mop500_sdi0_data = { - .ios_handler = mop500_sdi0_ios_handler, .ocr_mask = MMC_VDD_29_30, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | -- cgit v1.2.3 From 265c3c0a64df50c0e8fe55cfe8af8851ed5feca5 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 27 Mar 2013 14:13:53 +0000 Subject: ARM: ux500: Enable the clock controlling Ethernet on Snowball This fixes a regression introduced by common clk enablement. On some u8500 based boards, the FMSC clock which is usually used for flash, is wired up to the SMSC911x Ethernet driver. However, the SMSC911x doesn't have common clk support yet, rendering it unusable. Prior to the introduction of common clk the FMSC clock was default on; however, common clk disables all clocks by default and insists drivers take responsibility to enable theirs. This fix enables the FMSC clock on Snowball, subsequently turning on the SMSC911x Ethernet chip. It will be removed when the driver is compatible with common clk. Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/board-mop500.c | 12 ++++++++++++ arch/arm/mach-ux500/board-mop500.h | 1 + arch/arm/mach-ux500/cpu-db8500.c | 5 +++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index b03457881c4b..87d2d7b38ce9 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -439,6 +440,15 @@ static void mop500_prox_deactivate(struct device *dev) regulator_put(prox_regulator); } +void mop500_snowball_ethernet_clock_enable(void) +{ + struct clk *clk; + + clk = clk_get_sys("fsmc", NULL); + if (!IS_ERR(clk)) + clk_prepare_enable(clk); +} + static struct cryp_platform_data u8500_cryp1_platform_data = { .mem_to_engine = { .dir = STEDMA40_MEM_TO_PERIPH, @@ -683,6 +693,8 @@ static void __init snowball_init_machine(void) mop500_audio_init(parent); mop500_uart_init(parent); + mop500_snowball_ethernet_clock_enable(); + /* This board has full regulator constraints */ regulator_has_full_constraints(); } diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index eaa605f5d90d..d38951be70df 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -104,6 +104,7 @@ void __init mop500_pinmaps_init(void); void __init snowball_pinmaps_init(void); void __init hrefv60_pinmaps_init(void); void mop500_audio_init(struct device *parent); +void mop500_snowball_ethernet_clock_enable(void); int __init mop500_uib_init(void); void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info, diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 19235cf7bbe3..f1a581844372 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -312,9 +312,10 @@ static void __init u8500_init_machine(void) /* Pinmaps must be in place before devices register */ if (of_machine_is_compatible("st-ericsson,mop500")) mop500_pinmaps_init(); - else if (of_machine_is_compatible("calaosystems,snowball-a9500")) + else if (of_machine_is_compatible("calaosystems,snowball-a9500")) { snowball_pinmaps_init(); - else if (of_machine_is_compatible("st-ericsson,hrefv60+")) + mop500_snowball_ethernet_clock_enable(); + } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) hrefv60_pinmaps_init(); else if (of_machine_is_compatible("st-ericsson,ccu9540")) {} /* TODO: Add pinmaps for ccu9540 board. */ -- cgit v1.2.3 From 8abbbaf6adb46157b6bd416f7616b555cc6a332f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 27 Mar 2013 21:42:00 +0100 Subject: drm: don't unlock in the addfb error paths We don't grab the modeset locks any more since commit 468174f748603497e73dba9b5c6d1d9f71121486 Author: Daniel Vetter Date: Tue Dec 11 00:09:12 2012 +0100 drm: push modeset_lock_all into ->fb_create driver callbacks Reported-by: Ray Strode Cc: Ray Strode Cc: Dave Airlie Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 792c3e3795ca..dd64a06dc5b4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2326,7 +2326,6 @@ int drm_mode_addfb(struct drm_device *dev, fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); - drm_modeset_unlock_all(dev); return PTR_ERR(fb); } @@ -2506,7 +2505,6 @@ int drm_mode_addfb2(struct drm_device *dev, fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { DRM_DEBUG_KMS("could not create framebuffer\n"); - drm_modeset_unlock_all(dev); return PTR_ERR(fb); } -- cgit v1.2.3 From d79e57db84f8359bc96418900f86b8fc4189eff9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:22 +0100 Subject: ASoC: Constify the 'driver' field of snd_soc_platform The ASoC core does no not modify the driver of a platform. Making it const allows ASoC platform drivers to declare the snd_soc_platform_driver struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++-- sound/soc/soc-core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index c84062b22221..5fb70d1e8cce 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -371,7 +371,7 @@ int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, - struct snd_soc_platform_driver *platform_drv); + const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, @@ -823,7 +823,7 @@ struct snd_soc_platform { const char *name; int id; struct device *dev; - struct snd_soc_platform_driver *driver; + const struct snd_soc_platform_driver *driver; struct mutex mutex; unsigned int suspended:1; /* platform is suspended */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0ce075c47b25..4d24b5ea3ba7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3906,7 +3906,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); * @platform: platform to register */ int snd_soc_register_platform(struct device *dev, - struct snd_soc_platform_driver *platform_drv) + const struct snd_soc_platform_driver *platform_drv) { struct snd_soc_platform *platform; -- cgit v1.2.3 From 1f03f55b0ca679f950148954e807feb22cff325c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:23 +0100 Subject: ASoC: Constify the 'ops' field of snd_soc_platform_driver The ASoC core does not modify a platform driver's ops structure. Making it const allows ASoC platform drivers to declare their snd_pcm_ops struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 5fb70d1e8cce..966a854fc054 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -801,7 +801,7 @@ struct snd_soc_platform_driver { struct snd_soc_dai *); /* platform stream pcm ops */ - struct snd_pcm_ops *ops; + const struct snd_pcm_ops *ops; /* platform stream compress ops */ struct snd_compr_ops *compr_ops; -- cgit v1.2.3 From ef03c9ae967bf1b40bec1456f7e744033853a01d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:24 +0100 Subject: ASoC: Constify the 'compr_ops' field of snd_soc_platform_driver The ASoC core does not modify a platform driver's compr_ops structure. Making it const allows ASoC platform drivers to declare their snd_compr_ops struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 966a854fc054..f619905f0a65 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -804,7 +804,7 @@ struct snd_soc_platform_driver { const struct snd_pcm_ops *ops; /* platform stream compress ops */ - struct snd_compr_ops *compr_ops; + const struct snd_compr_ops *compr_ops; /* platform stream completion event */ int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); -- cgit v1.2.3 From a96f5e9394d298689eb3b876e6619166f1a37cc4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 27 Mar 2013 10:50:53 +0000 Subject: ASoC: wm5102: Correctly use SOC_VALUE_ENUM for ISRC FSL controls Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index a1ff43c8b479..d1b43ebec087 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -762,8 +762,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), -SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), -- cgit v1.2.3 From fa40ef208c955bfe21f53913f51f297ac3237e95 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 27 Mar 2013 16:39:01 +0000 Subject: ASoC: compress: Cancel delayed power down if needed When a new stream is being opened it is necessary to cancel any delayed power down of the audio. [Fixed unused variable -- broonie] Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index b5b3db71e253..ed0bfb0ddb96 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -211,19 +211,27 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) - goto out; + goto err; } if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); if (ret < 0) - goto out; + goto err; } snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_START); -out: + /* cancel any delayed stream shutdown that is pending */ + rtd->pop_wait = 0; + mutex_unlock(&rtd->pcm_mutex); + + cancel_delayed_work_sync(&rtd->delayed_work); + + return ret; + +err: mutex_unlock(&rtd->pcm_mutex); return ret; } -- cgit v1.2.3 From adaa4b8e4d47eeb114513c2f7a172929154b94bd Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 21 Mar 2013 14:30:23 +0000 Subject: Btrfs: fix EIO from btrfs send in is_extent_unchanged for punched holes When you take a snapshot, punch a hole where there has been data, then take another snapshot and try to send an incremental stream, btrfs send would give you EIO. That is because is_extent_unchanged had no support for holes being punched. With this patch, instead of returning EIO we just return 0 (== the extent is not unchanged) and we're good. Signed-off-by: Jan Schmidt Cc: Alexander Block Signed-off-by: Josef Bacik --- fs/btrfs/send.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 68da757615ae..ed897dc11356 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3945,12 +3945,10 @@ static int is_extent_unchanged(struct send_ctx *sctx, found_key.type != key.type) { key.offset += right_len; break; - } else { - if (found_key.offset != key.offset + right_len) { - /* Should really not happen */ - ret = -EIO; - goto out; - } + } + if (found_key.offset != key.offset + right_len) { + ret = 0; + goto out; } key = found_key; } -- cgit v1.2.3 From f4881bc7a83eff263789dd524b7c269d138d4af5 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 25 Mar 2013 16:03:35 -0400 Subject: Btrfs: fix space leak when we fail to reserve metadata space Dave reported a warning when running xfstest 275. We have been leaking delalloc metadata space when our reservations fail. This is because we were improperly calculating how much space to free for our checksum reservations. The problem is we would sometimes free up space that had already been freed in another thread and we would end up with negative usage for the delalloc space. This patch fixes the problem by calculating how much space the other threads would have already freed, and then calculate how much space we need to free had we not done the reservation at all, and then freeing any excess space. This makes xfstests 275 no longer have leaked space. Thanks Cc: stable@vger.kernel.org Reported-by: David Sterba Signed-off-by: Josef Bacik --- fs/btrfs/extent-tree.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a8ff25aedca1..a22b5cc921ad 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4815,14 +4815,49 @@ out_fail: * If the inodes csum_bytes is the same as the original * csum_bytes then we know we haven't raced with any free()ers * so we can just reduce our inodes csum bytes and carry on. - * Otherwise we have to do the normal free thing to account for - * the case that the free side didn't free up its reserve - * because of this outstanding reservation. */ - if (BTRFS_I(inode)->csum_bytes == csum_bytes) + if (BTRFS_I(inode)->csum_bytes == csum_bytes) { calc_csum_metadata_size(inode, num_bytes, 0); - else - to_free = calc_csum_metadata_size(inode, num_bytes, 0); + } else { + u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes; + u64 bytes; + + /* + * This is tricky, but first we need to figure out how much we + * free'd from any free-ers that occured during this + * reservation, so we reset ->csum_bytes to the csum_bytes + * before we dropped our lock, and then call the free for the + * number of bytes that were freed while we were trying our + * reservation. + */ + bytes = csum_bytes - BTRFS_I(inode)->csum_bytes; + BTRFS_I(inode)->csum_bytes = csum_bytes; + to_free = calc_csum_metadata_size(inode, bytes, 0); + + + /* + * Now we need to see how much we would have freed had we not + * been making this reservation and our ->csum_bytes were not + * artificially inflated. + */ + BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes; + bytes = csum_bytes - orig_csum_bytes; + bytes = calc_csum_metadata_size(inode, bytes, 0); + + /* + * Now reset ->csum_bytes to what it should be. If bytes is + * more than to_free then we would have free'd more space had we + * not had an artificially high ->csum_bytes, so we need to free + * the remainder. If bytes is the same or less then we don't + * need to do anything, the other free-ers did the correct + * thing. + */ + BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes; + if (bytes > to_free) + to_free = bytes - to_free; + else + to_free = 0; + } spin_unlock(&BTRFS_I(inode)->lock); if (dropped) to_free += btrfs_calc_trans_metadata_size(root, dropped); -- cgit v1.2.3 From 6e137ed3f30574f314733d4b7a86ea6523232b14 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 26 Mar 2013 15:26:55 -0400 Subject: Btrfs: fix space accounting for unlink and rename We are way over-reserving for unlink and rename. Rename is just some random huge number and unlink accounts for tree log operations that don't actually happen during unlink, not to mention the tree log doesn't take from the trans block rsv anyway so it's completely useless. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/inode.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6a6e13c53086..8cab424c75f8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3693,11 +3693,9 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir, * 1 for the dir item * 1 for the dir index * 1 for the inode ref - * 1 for the inode ref in the tree log - * 2 for the dir entries in the log * 1 for the inode */ - trans = btrfs_start_transaction(root, 8); + trans = btrfs_start_transaction(root, 5); if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) return trans; @@ -8141,7 +8139,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, * inodes. So 5 * 2 is 10, plus 1 for the new link, so 11 total items * should cover the worst case number of items we'll modify. */ - trans = btrfs_start_transaction(root, 20); + trans = btrfs_start_transaction(root, 11); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_notrans; -- cgit v1.2.3 From db1d607d3ca5cbb283cbb17d648cd7e8dc67cc7b Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 26 Mar 2013 15:29:11 -0400 Subject: Btrfs: hold the ordered operations mutex when waiting on ordered extents We need to hold the ordered_operations mutex while waiting on ordered extents since we splice and run the ordered extents list. We need to make sure anybody else who wants to wait on ordered extents does actually wait for them to be completed. This will keep us from bailing out of flushing in case somebody is already waiting on ordered extents to complete. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index dc08d77b717e..005c45db699e 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -557,6 +557,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) INIT_LIST_HEAD(&splice); INIT_LIST_HEAD(&works); + mutex_lock(&root->fs_info->ordered_operations_mutex); spin_lock(&root->fs_info->ordered_extent_lock); list_splice_init(&root->fs_info->ordered_extents, &splice); while (!list_empty(&splice)) { @@ -600,6 +601,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) cond_resched(); } + mutex_unlock(&root->fs_info->ordered_operations_mutex); } /* -- cgit v1.2.3 From fdf30d1c1b386e1b73116cc7e0fb14e962b763b0 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 26 Mar 2013 15:31:45 -0400 Subject: Btrfs: limit the global reserve to 512mb A user reported a problem where he was getting early ENOSPC with hundreds of gigs of free data space and 6 gigs of free metadata space. This is because the global block reserve was taking up the entire free metadata space. This is ridiculous, we have infrastructure in place to throttle if we start using too much of the global reserve, so instead of letting it get this huge just limit it to 512mb so that users can still get work done. This allowed the user to complete his rsync without issues. Thanks Cc: stable@vger.kernel.org Reported-and-tested-by: Stefan Priebe Signed-off-by: Josef Bacik --- fs/btrfs/extent-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a22b5cc921ad..0d8478700d78 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4460,7 +4460,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info) spin_lock(&sinfo->lock); spin_lock(&block_rsv->lock); - block_rsv->size = num_bytes; + block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024); num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + sinfo->bytes_reserved + sinfo->bytes_readonly + -- cgit v1.2.3 From a7975026ff9ddf91ba190ae2b71699dd156395e3 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Mon, 25 Mar 2013 11:08:23 +0000 Subject: Btrfs: fix double free in the btrfs_qgroup_account_ref() The function btrfs_find_all_roots is responsible to allocate memory for 'roots' and free it if errors happen,so the caller should not free it again since the work has been done. Besides,'tmp' is allocated after the function btrfs_find_all_roots, so we can return directly if btrfs_find_all_roots() fails. Signed-off-by: Wang Shilong Reviewed-by: Miao Xie Reviewed-by: Jan Schmidt Signed-off-by: Josef Bacik --- fs/btrfs/qgroup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 5471e47d6559..b44124dd2370 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1153,7 +1153,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, ret = btrfs_find_all_roots(trans, fs_info, node->bytenr, sgn > 0 ? node->seq - 1 : node->seq, &roots); if (ret < 0) - goto out; + return ret; spin_lock(&fs_info->qgroup_lock); quota_root = fs_info->quota_root; @@ -1275,7 +1275,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, ret = 0; unlock: spin_unlock(&fs_info->qgroup_lock); -out: ulist_free(roots); ulist_free(tmp); -- cgit v1.2.3 From 39847c4d3d91f487f9ab3d083ee5d0f8419f105c Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 28 Mar 2013 08:08:20 +0000 Subject: Btrfs: fix wrong reservation of csums We reserve the space for csums only when we write data into a file, in the other cases, such as tree log, log replay, we don't do reservation, so we can use the reservation of the transaction handle just for the former. And for the latter, we should use the tree's own reservation. But the function - btrfs_csum_file_blocks() didn't differentiate between these two types of the cases, fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file-item.c | 2 -- fs/btrfs/inode.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index ec160202be3e..b7e529d2860f 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -728,7 +728,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, return -ENOMEM; sector_sum = sums->sums; - trans->adding_csums = 1; again: next_offset = (u64)-1; found_next = 0; @@ -899,7 +898,6 @@ next_sector: goto again; } out: - trans->adding_csums = 0; btrfs_free_path(path); return ret; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8cab424c75f8..b88381582dab 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1757,8 +1757,10 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, struct btrfs_ordered_sum *sum; list_for_each_entry(sum, list, list) { + trans->adding_csums = 1; btrfs_csum_file_blocks(trans, BTRFS_I(inode)->root->fs_info->csum_root, sum); + trans->adding_csums = 0; } return 0; } -- cgit v1.2.3 From 82d130ff390be67d980d8b6f39e921c0b1d8d8e0 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 28 Mar 2013 08:12:15 +0000 Subject: Btrfs: fix wrong return value of btrfs_lookup_csum() If we don't find the expected csum item, but find a csum item which is adjacent to the specified extent, we should return -EFBIG, or we should return -ENOENT. But btrfs_lookup_csum() return -EFBIG even the csum item is not adjacent to the specified extent. Fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file-item.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index b7e529d2860f..c4628a201cb3 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -118,9 +118,11 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); csums_in_item /= csum_size; - if (csum_offset >= csums_in_item) { + if (csum_offset == csums_in_item) { ret = -EFBIG; goto fail; + } else if (csum_offset > csums_in_item) { + goto fail; } } item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); -- cgit v1.2.3 From b8730b403aee94db4631bfefb546a6ce8c287dc2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Mar 2013 20:49:58 +0100 Subject: iwlwifi: dvm: fix the passive-no-RX workaround Alex Romosan reported that since the mac80211 changes in "mac80211: start auth/assoc timeout on frame status" and the subsequent fixes in "mac80211: fix auth/assoc timeout handling" (commits 1672c0e31917 and 89afe614c0c) there's sometimes an issue connecting to a 5 GHz network with the iwlwifi DVM driver. The reason appears to be that since these commits any bad TX status makes mac80211 immediately try again, causing all of the authentication attempts to be quickly rejected by the firmware as it hasn't heard a beacon yet. Before, it would wait for the timeout regardless of status. To fix this, invoke the passive-no-RX workaround when not associated yet as well. This will cause the first frame to get lost, but then the driver will stop the queues and the second attempt will only be transmitted after hearing a beacon, thus delaying it appropriately to not make the firmware reject it again. Reported-by: Alex Romosan Tested-by: Alex Romosan Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/rxon.c | 18 ++++++++---------- drivers/net/wireless/iwlwifi/dvm/tx.c | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 23be948cf162..a82b6b39d4ff 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1419,6 +1419,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { + /* + * If we go idle, then clearly no "passive-no-rx" + * workaround is needed any more, this is a reset. + */ + iwlagn_lift_passive_no_rx(priv); + } + if (unlikely(!iwl_is_ready(priv))) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); mutex_unlock(&priv->mutex); @@ -1450,16 +1458,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, priv->timestamp = bss_conf->sync_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { - /* - * If we disassociate while there are pending - * frames, just wake up the queues and let the - * frames "escape" ... This shouldn't really - * be happening to start with, but we should - * not get stuck in this case either since it - * can happen if userspace gets confused. - */ - iwlagn_lift_passive_no_rx(priv); - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; if (ctx->ctxid == IWL_RXON_CTX_BSS) diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 6aec2df3bb27..d1a670d7b10c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1192,7 +1192,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, memset(&info->status, 0, sizeof(info->status)); if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && - iwl_is_associated_ctx(ctx) && ctx->vif && + ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) { /* block and stop all queues */ priv->passive_no_rx = true; -- cgit v1.2.3 From c613c5f686b5493290aeb6a3c4b3b2371a8582cf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 28 Mar 2013 09:43:43 -0600 Subject: mg_disk: fix error return code in mg_probe() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Reviewed-by: Jingoo Han Signed-off-by: Jens Axboe --- drivers/block/mg_disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 1788f491e0fb..076ae7f1b781 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -890,8 +890,10 @@ static int mg_probe(struct platform_device *plat_dev) gpio_direction_output(host->rst, 1); /* reset out pin */ - if (!(prv_data->dev_attr & MG_DEV_MASK)) + if (!(prv_data->dev_attr & MG_DEV_MASK)) { + err = -EINVAL; goto probe_err_3a; + } if (prv_data->dev_attr != MG_BOOT_DEV) { rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, -- cgit v1.2.3 From 482b0b5d82bd916cc0c55a2abf65bdc69023b843 Mon Sep 17 00:00:00 2001 From: Konstantin Holoborodko Date: Fri, 29 Mar 2013 00:06:13 +0900 Subject: usb: ftdi_sio: Add support for Mitsubishi FX-USB-AW/-BD It enhances the driver for FTDI-based USB serial adapters to recognize Mitsubishi Electric Corp. USB/RS422 Converters as FT232BM chips and support them. https://search.meau.com/?q=FX-USB-AW Signed-off-by: Konstantin Holoborodko Tested-by: Konstantin Holoborodko Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d4809d551473..9886180e45f1 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -640,6 +640,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 9d359e189a64..e79861eeed4c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -583,6 +583,13 @@ #define CONTEC_VID 0x06CE /* Vendor ID */ #define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ +/* + * Mitsubishi Electric Corp. (http://www.meau.com) + * Submitted by Konstantin Holoborodko + */ +#define MITSUBISHI_VID 0x06D3 +#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */ + /* * Definitions for B&B Electronics products. */ -- cgit v1.2.3 From 2992714d431976c4b154875bd18ba61bf4df3b93 Mon Sep 17 00:00:00 2001 From: Eric Hutter Date: Mon, 18 Mar 2013 19:48:56 +0100 Subject: ARM: kirkwood: Fix chip-delay for GoFlex Net This fixes "Too few good blocks within range" issues on GoFlex Net by setting chip-delay to 40. The basic problem was discussed at http://forum.doozan.com/read.php?2,7451 Signed-off-by: Eric Hutter Acked-by: Andrew Lunn Cc: # v3.6.x Signed-off-by: Jason Cooper --- arch/arm/boot/dts/kirkwood-goflexnet.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/kirkwood-goflexnet.dts b/arch/arm/boot/dts/kirkwood-goflexnet.dts index bd83b8fc7c83..c3573be7b92c 100644 --- a/arch/arm/boot/dts/kirkwood-goflexnet.dts +++ b/arch/arm/boot/dts/kirkwood-goflexnet.dts @@ -77,6 +77,7 @@ }; nand@3000000 { + chip-delay = <40>; status = "okay"; partition@0 { -- cgit v1.2.3 From 7f23f62fc31c5c97947414c0937a72e08a947a41 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 20 Mar 2013 16:09:35 +0100 Subject: arm: mvebu: Use local interrupt only for the timer 0 The commit 3a6f08a37 "arm: mvebu: Add support for local interrupt", managed the 28th first interrupts as local interrupt to match the hardware specification. Among these interrupts there are the Gigabits Ethernet ones used by the mvneta driver. Unfortunately the state of the percpu_irq API prevents the driver to use it. Indeed the interrupts have to be freed when the .stop() function is called. As the free_percpu_irq() function don't disable the interrupt line, we have to do it on each CPU before calling this. The function disable_percpu_irq() only disable the percpu on the current CPU and there is no function which allows to disable a percpu irq on a given CPU. Waiting for the extension of the percpu_irq API, this fix allows to use again the mvneta driver. Signed-off-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Tested-by: Masami Hiramatsu Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/irq-armada-370-xp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c index 274ff58271de..6a9195e10579 100644 --- a/arch/arm/mach-mvebu/irq-armada-370-xp.c +++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c @@ -44,6 +44,8 @@ #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) +#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) + #define ACTIVE_DOORBELLS (8) static DEFINE_RAW_SPINLOCK(irq_controller_lock); @@ -62,7 +64,7 @@ static void armada_370_xp_irq_mask(struct irq_data *d) #ifdef CONFIG_SMP irq_hw_number_t hwirq = irqd_to_hwirq(d); - if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS) + if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) writel(hwirq, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); else @@ -79,7 +81,7 @@ static void armada_370_xp_irq_unmask(struct irq_data *d) #ifdef CONFIG_SMP irq_hw_number_t hwirq = irqd_to_hwirq(d); - if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS) + if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) writel(hwirq, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); else @@ -147,7 +149,7 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); irq_set_status_flags(virq, IRQ_LEVEL); - if (hw < ARMADA_370_XP_MAX_PER_CPU_IRQS) { + if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) { irq_set_percpu_devid(virq); irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, handle_percpu_devid_irq); -- cgit v1.2.3 From 0d0644ebc63bce3784ebea28d0355071b4e90525 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sat, 23 Mar 2013 13:56:58 +0100 Subject: ARM: Kirkwood: fix unused mvsdio gpio pins mvsdio_platform_data allows to pass card detect and write protect gpio numbers to the driver. Some kirkwood boards don't use both pins as they are not connected, and don't set the corresponding value in platform_data. This will leave the unset values in platform_data initialized as 0, which is in fact a valid gpio pin. mvsdio will grab that pin and configure it as gpio, which in turn breaks nand controller as mpp0 also carries nand_io2. This patch fixes the above by initializing unused gpio functions in the platform_data with an invalid (-1) value. Signed-off-by: Sebastian Hesselbarth Reported-by: Soeren Moch Signed-off-by: Jason Cooper --- arch/arm/mach-kirkwood/guruplug-setup.c | 2 ++ arch/arm/mach-kirkwood/openrd-setup.c | 1 + arch/arm/mach-kirkwood/rd88f6281-setup.c | 1 + 3 files changed, 4 insertions(+) diff --git a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c index 1c6e736cbbf8..08dd739aa709 100644 --- a/arch/arm/mach-kirkwood/guruplug-setup.c +++ b/arch/arm/mach-kirkwood/guruplug-setup.c @@ -53,6 +53,8 @@ static struct mv_sata_platform_data guruplug_sata_data = { static struct mvsdio_platform_data guruplug_mvsdio_data = { /* unfortunately the CD signal has not been connected */ + .gpio_card_detect = -1, + .gpio_write_protect = -1, }; static struct gpio_led guruplug_led_pins[] = { diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c index 8ddd69fdc937..6a6eb548307d 100644 --- a/arch/arm/mach-kirkwood/openrd-setup.c +++ b/arch/arm/mach-kirkwood/openrd-setup.c @@ -55,6 +55,7 @@ static struct mv_sata_platform_data openrd_sata_data = { static struct mvsdio_platform_data openrd_mvsdio_data = { .gpio_card_detect = 29, /* MPP29 used as SD card detect */ + .gpio_write_protect = -1, }; static unsigned int openrd_mpp_config[] __initdata = { diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c index c7d93b48926b..d24223166e06 100644 --- a/arch/arm/mach-kirkwood/rd88f6281-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c @@ -69,6 +69,7 @@ static struct mv_sata_platform_data rd88f6281_sata_data = { static struct mvsdio_platform_data rd88f6281_mvsdio_data = { .gpio_card_detect = 28, + .gpio_write_protect = -1, }; static unsigned int rd88f6281_mpp_config[] __initdata = { -- cgit v1.2.3 From 835f6322c691600da5b7fb526f07b1d21d0c88ef Mon Sep 17 00:00:00 2001 From: Alexander Clouter Date: Tue, 26 Mar 2013 21:44:46 +0000 Subject: arm: orion5x: fix orion5x.dtsi gpio parameters orion5x.dtsi is missing the gpio alias as well as including a typo ('ngpio' instead of 'ngpios') that prevented the orion-gpio driver from loading. Also missing were the interrupt-controller properties. This patches resolves those glitches. Signed-off-by: Alexander Clouter Acked-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/boot/dts/orion5x.dtsi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi index 8aad00f81ed9..7c2a3263c166 100644 --- a/arch/arm/boot/dts/orion5x.dtsi +++ b/arch/arm/boot/dts/orion5x.dtsi @@ -13,6 +13,9 @@ compatible = "marvell,orion5x"; interrupt-parent = <&intc>; + aliases { + gpio0 = &gpio0; + }; intc: interrupt-controller { compatible = "marvell,orion-intc", "marvell,intc"; interrupt-controller; @@ -32,7 +35,9 @@ #gpio-cells = <2>; gpio-controller; reg = <0x10100 0x40>; - ngpio = <32>; + ngpios = <32>; + interrupt-controller; + #interrupt-cells = <2>; interrupts = <6>, <7>, <8>, <9>; }; -- cgit v1.2.3 From e0656a9cbbd0444aaec493ed8a9420d07c356639 Mon Sep 17 00:00:00 2001 From: Alexander Clouter Date: Tue, 26 Mar 2013 21:44:49 +0000 Subject: arm: orion5x: correct IRQ used in dtsi for mv_cesa The crypto functionality in the orion5x dtsi uses the Ethernet IRQ and so things do not work and there is much grumbling at boot time. The IRQ for the crypto should be 28, and not 22, and that is what this patch corrects. Signed-off-by: Alexander Clouter Acked-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/boot/dts/orion5x.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi index 7c2a3263c166..f7bec3b1ba32 100644 --- a/arch/arm/boot/dts/orion5x.dtsi +++ b/arch/arm/boot/dts/orion5x.dtsi @@ -96,7 +96,7 @@ reg = <0x90000 0x10000>, <0xf2200000 0x800>; reg-names = "regs", "sram"; - interrupts = <22>; + interrupts = <28>; status = "okay"; }; }; -- cgit v1.2.3 From 879d68a445dd7073a8c022fcdd21dc27eca7f192 Mon Sep 17 00:00:00 2001 From: Ryan Press Date: Tue, 26 Mar 2013 16:32:31 -0700 Subject: arm: mvebu: Fix pinctrl for Armada 370 Mirabox SDIO port. The previous configuration used the wrong "clk" pin. Without this change mv_sdio worked because the bootloader would set the pin up, but with a bootloader that does not set the pin, mv_sdio fails to detect any card. I have tested this change using a mwifiex_sdio wireless network adapter over the SDIO interface. Signed-off-by: Ryan Press Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-370-mirabox.dts | 2 +- arch/arm/boot/dts/armada-370.dtsi | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts index dd0c57dd9f30..3234875824dc 100644 --- a/arch/arm/boot/dts/armada-370-mirabox.dts +++ b/arch/arm/boot/dts/armada-370-mirabox.dts @@ -54,7 +54,7 @@ }; mvsdio@d00d4000 { - pinctrl-0 = <&sdio_pins2>; + pinctrl-0 = <&sdio_pins3>; pinctrl-names = "default"; status = "okay"; /* diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi index 8188d138020e..a195debb67d3 100644 --- a/arch/arm/boot/dts/armada-370.dtsi +++ b/arch/arm/boot/dts/armada-370.dtsi @@ -59,6 +59,12 @@ "mpp50", "mpp51", "mpp52"; marvell,function = "sd0"; }; + + sdio_pins3: sdio-pins3 { + marvell,pins = "mpp48", "mpp49", "mpp50", + "mpp51", "mpp52", "mpp53"; + marvell,function = "sd0"; + }; }; gpio0: gpio@d0018100 { -- cgit v1.2.3 From 91c5746425aed8f7188a351f1224a26aa232e4b3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Mar 2013 18:28:41 +0000 Subject: aoe: reserve enough headroom on skbs Some network drivers use a non default hard_header_len Transmitted skb should take into account dev->hard_header_len, or risk crashes or expensive reallocations. In the case of aoe, lets reserve MAX_HEADER bytes. David reported a crash in defxx driver, solved by this patch. Reported-by: David Oostdyk Tested-by: David Oostdyk Signed-off-by: Eric Dumazet Cc: Ed Cashin Signed-off-by: David S. Miller --- drivers/block/aoe/aoecmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 25ef5c014fca..92b6d7c51e39 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -51,8 +51,9 @@ new_skb(ulong len) { struct sk_buff *skb; - skb = alloc_skb(len, GFP_ATOMIC); + skb = alloc_skb(len + MAX_HEADER, GFP_ATOMIC); if (skb) { + skb_reserve(skb, MAX_HEADER); skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->protocol = __constant_htons(ETH_P_AOE); -- cgit v1.2.3 From 09a9f1d27892255cfb9c91203f19476765e2d8d1 Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Thu, 28 Mar 2013 16:26:23 -0700 Subject: Revert "mm: introduce VM_POPULATE flag to better deal with racy userspace programs" This reverts commit 186930500985 ("mm: introduce VM_POPULATE flag to better deal with racy userspace programs"). VM_POPULATE only has any effect when userspace plays racy games with vmas by trying to unmap and remap memory regions that mmap or mlock are operating on. Also, the only effect of VM_POPULATE when userspace plays such games is that it avoids populating new memory regions that get remapped into the address range that was being operated on by the original mmap or mlock calls. Let's remove VM_POPULATE as there isn't any strong argument to mandate a new vm_flag. Signed-off-by: Michel Lespinasse Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 - include/linux/mman.h | 4 +--- mm/fremap.c | 12 ++---------- mm/mlock.c | 11 +++++------ mm/mmap.c | 4 +++- 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7acc9dc73c9f..e19ff30ad0a2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -87,7 +87,6 @@ extern unsigned int kobjsize(const void *objp); #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ #define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ -#define VM_POPULATE 0x00001000 #define VM_LOCKED 0x00002000 #define VM_IO 0x00004000 /* Memory mapped I/O or similar */ diff --git a/include/linux/mman.h b/include/linux/mman.h index 61c7a87e5d2b..9aa863da287f 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -79,8 +79,6 @@ calc_vm_flag_bits(unsigned long flags) { return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | - ((flags & MAP_LOCKED) ? (VM_LOCKED | VM_POPULATE) : 0) | - (((flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE) ? - VM_POPULATE : 0); + _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); } #endif /* _LINUX_MMAN_H */ diff --git a/mm/fremap.c b/mm/fremap.c index 4723ac8d2fc2..87da3590c61e 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -204,10 +204,8 @@ get_write_lock: unsigned long addr; struct file *file = get_file(vma->vm_file); - vm_flags = vma->vm_flags; - if (!(flags & MAP_NONBLOCK)) - vm_flags |= VM_POPULATE; - addr = mmap_region(file, start, size, vm_flags, pgoff); + addr = mmap_region(file, start, size, + vma->vm_flags, pgoff); fput(file); if (IS_ERR_VALUE(addr)) { err = addr; @@ -226,12 +224,6 @@ get_write_lock: mutex_unlock(&mapping->i_mmap_mutex); } - if (!(flags & MAP_NONBLOCK) && !(vma->vm_flags & VM_POPULATE)) { - if (!has_write_lock) - goto get_write_lock; - vma->vm_flags |= VM_POPULATE; - } - if (vma->vm_flags & VM_LOCKED) { /* * drop PG_Mlocked flag for over-mapped range diff --git a/mm/mlock.c b/mm/mlock.c index 1c5e33fce639..79b7cf7d1bca 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -358,7 +358,7 @@ static int do_mlock(unsigned long start, size_t len, int on) newflags = vma->vm_flags & ~VM_LOCKED; if (on) - newflags |= VM_LOCKED | VM_POPULATE; + newflags |= VM_LOCKED; tmp = vma->vm_end; if (tmp > end) @@ -418,8 +418,7 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors) * range with the first VMA. Also, skip undesirable VMA types. */ nend = min(end, vma->vm_end); - if ((vma->vm_flags & (VM_IO | VM_PFNMAP | VM_POPULATE)) != - VM_POPULATE) + if (vma->vm_flags & (VM_IO | VM_PFNMAP)) continue; if (nstart < vma->vm_start) nstart = vma->vm_start; @@ -492,9 +491,9 @@ static int do_mlockall(int flags) struct vm_area_struct * vma, * prev = NULL; if (flags & MCL_FUTURE) - current->mm->def_flags |= VM_LOCKED | VM_POPULATE; + current->mm->def_flags |= VM_LOCKED; else - current->mm->def_flags &= ~(VM_LOCKED | VM_POPULATE); + current->mm->def_flags &= ~VM_LOCKED; if (flags == MCL_FUTURE) goto out; @@ -503,7 +502,7 @@ static int do_mlockall(int flags) newflags = vma->vm_flags & ~VM_LOCKED; if (flags & MCL_CURRENT) - newflags |= VM_LOCKED | VM_POPULATE; + newflags |= VM_LOCKED; /* Ignore errors */ mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); diff --git a/mm/mmap.c b/mm/mmap.c index 2664a47cec93..6466699b16cb 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1306,7 +1306,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, } addr = mmap_region(file, addr, len, vm_flags, pgoff); - if (!IS_ERR_VALUE(addr) && (vm_flags & VM_POPULATE)) + if (!IS_ERR_VALUE(addr) && + ((vm_flags & VM_LOCKED) || + (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE)) *populate = len; return addr; } -- cgit v1.2.3 From b43decd2c513ae44a5462a1a4c2622f0fa77c9e0 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Sun, 24 Mar 2013 15:36:38 +0100 Subject: drm/nouveau: fix handling empty channel list in ioctl's If there are no channels, chan would never end up being NULL, and so the null pointer check would fail. Solve this by initializing chan to NULL, and iterating over temp instead. Fixes oops when running intel-gpu-tools/tests/kms_flip, which attempts to do some intel ioctl's on a nouveau device. Signed-off-by: Maarten Lankhorst Cc: stable@vger.kernel.org [3.7+] Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 3b6dc883e150..5eb3e0da7c6e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -391,7 +391,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_device *device = nv_device(drm->device); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); - struct nouveau_abi16_chan *chan, *temp; + struct nouveau_abi16_chan *chan = NULL, *temp; struct nouveau_abi16_ntfy *ntfy; struct nouveau_object *object; struct nv_dma_class args = {}; @@ -404,10 +404,11 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) return nouveau_abi16_put(abi16, -EINVAL); - list_for_each_entry_safe(chan, temp, &abi16->channels, head) { - if (chan->chan->handle == (NVDRM_CHAN | info->channel)) + list_for_each_entry(temp, &abi16->channels, head) { + if (temp->chan->handle == (NVDRM_CHAN | info->channel)) { + chan = temp; break; - chan = NULL; + } } if (!chan) @@ -459,17 +460,18 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) { struct drm_nouveau_gpuobj_free *fini = data; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); - struct nouveau_abi16_chan *chan, *temp; + struct nouveau_abi16_chan *chan = NULL, *temp; struct nouveau_abi16_ntfy *ntfy; int ret; if (unlikely(!abi16)) return -ENOMEM; - list_for_each_entry_safe(chan, temp, &abi16->channels, head) { - if (chan->chan->handle == (NVDRM_CHAN | fini->channel)) + list_for_each_entry(temp, &abi16->channels, head) { + if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) { + chan = temp; break; - chan = NULL; + } } if (!chan) -- cgit v1.2.3 From e4604d8fe8492f8120cf92d4b60b3cc90ba87bd0 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Sun, 24 Mar 2013 12:56:30 +0100 Subject: drm/nouveau: fix NULL ptr dereference from nv50_disp_intr() Op 23-03-13 12:47, Peter Hurley schreef: > On Tue, 2013-03-19 at 11:13 -0400, Peter Hurley wrote: >> On vanilla 3.9.0-rc3, I get this 100% repeatable oops after login when >> the user X session is coming up: > Perhaps I wasn't clear that this happens on every boot and is a > regression from 3.8 > > I'd be happy to help resolve this but time is of the essence; it would > be a shame to have to revert all of this for 3.9 Well it broke on my system too, so it was easy to fix. I didn't even need gdm to trigger it! >8---- This fixes regression caused by 1d7c71a3e2f7 (drm/nouveau/disp: port vblank handling to event interface), which causes a oops in the following way: BUG: unable to handle kernel NULL pointer dereference at 0000000000000001 IP: [<0000000000000001>] 0x0 PGD 0 Oops: 0010 [#1] PREEMPT SMP Modules linked in: ip6table_filter ip6_tables ebtable_nat ebtables ...... CPU 3 Pid: 0, comm: swapper/3 Not tainted 3.9.0-rc3-xeon #rc3 Dell Inc. Precision WorkStation T5400 /0RW203 RIP: 0010:[<0000000000000001>] [<0000000000000001>] 0x0 RSP: 0018:ffff8802afcc3d80 EFLAGS: 00010087 RAX: ffff88029f6e5808 RBX: 0000000000000001 RCX: 0000000000000000 RDX: 0000000000000096 RSI: 0000000000000001 RDI: ffff88029f6e5808 RBP: ffff8802afcc3dc8 R08: 0000000000000000 R09: 0000000000000004 R10: 000000000000002c R11: ffff88029e559a98 R12: ffff8802a376cb78 R13: ffff88029f6e57e0 R14: ffff88029f6e57f8 R15: ffff88029f6e5808 FS: 0000000000000000(0000) GS:ffff8802afcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000001 CR3: 000000029fa67000 CR4: 00000000000007e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper/3 (pid: 0, threadinfo ffff8802a355e000, task ffff8802a3535c40) Stack: ffffffffa0159d8a 0000000000000082 ffff88029f6e5820 0000000000000001 ffff88029f71aa00 0000000000000000 0000000000000000 0000000004000000 0000000004000000 ffff8802afcc3e38 ffffffffa01843b5 ffff8802afcc3df8 Call Trace: [] ? nouveau_event_trigger+0xaa/0xe0 [nouveau] [] nv50_disp_intr+0xc5/0x200 [nouveau] [] ? _raw_spin_unlock_irqrestore+0x2c/0x50 [] ? notifier_call_chain+0x4d/0x70 [] nouveau_mc_intr+0xb5/0x110 [nouveau] [] nouveau_irq_handler+0x6f/0x80 [nouveau] [] handle_irq_event_percpu+0x75/0x260 [] handle_irq_event+0x48/0x70 [] handle_fasteoi_irq+0x5a/0x100 [] handle_irq+0x22/0x40 [] do_IRQ+0x5a/0xd0 [] common_interrupt+0x6d/0x6d [] ? native_safe_halt+0x6/0x10 [] default_idle+0x3d/0x170 [] cpu_idle+0x116/0x130 [] start_secondary+0x251/0x258 Code: Bad RIP value. RIP [<0000000000000001>] 0x0 RSP CR2: 0000000000000001 ---[ end trace 907323cb8ce6f301 ]--- Signed-off-by: Maarten Lankhorst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 32 ++++++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_drm.h | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index d1099365bfc1..c95decf543e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -71,12 +71,26 @@ module_param_named(modeset, nouveau_modeset, int, 0400); static struct drm_driver driver; +static int +nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) +{ + struct nouveau_drm *drm = + container_of(event, struct nouveau_drm, vblank[head]); + drm_handle_vblank(drm->dev, head); + return NVKM_EVENT_KEEP; +} + static int nouveau_drm_vblank_enable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); - nouveau_event_get(pdisp->vblank, head, &drm->vblank); + + if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank))) + return -EIO; + WARN_ON_ONCE(drm->vblank[head].func); + drm->vblank[head].func = nouveau_drm_vblank_handler; + nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]); return 0; } @@ -85,16 +99,11 @@ nouveau_drm_vblank_disable(struct drm_device *dev, int head) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); - nouveau_event_put(pdisp->vblank, head, &drm->vblank); -} - -static int -nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) -{ - struct nouveau_drm *drm = - container_of(event, struct nouveau_drm, vblank); - drm_handle_vblank(drm->dev, head); - return NVKM_EVENT_KEEP; + if (drm->vblank[head].func) + nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]); + else + WARN_ON_ONCE(1); + drm->vblank[head].func = NULL; } static u64 @@ -292,7 +301,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = drm; drm->dev = dev; - drm->vblank.func = nouveau_drm_vblank_handler; INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index b25df374c901..9c39bafbef2c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -113,7 +113,7 @@ struct nouveau_drm { struct nvbios vbios; struct nouveau_display *display; struct backlight_device *backlight; - struct nouveau_eventh vblank; + struct nouveau_eventh vblank[4]; /* power management */ struct nouveau_pm *pm; -- cgit v1.2.3 From 5dade71050e799d8679698a6145e2ba46cdeac2a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 27 Mar 2013 17:23:41 -0700 Subject: tcm_vhost: Avoid VIRTIO_RING_F_EVENT_IDX feature bit This patch adds a VHOST_SCSI_FEATURES mask minus VIRTIO_RING_F_EVENT_IDX so that vhost-scsi-pci userspace will strip this feature bit once GET_FEATURES reports it as being unsupported on the host. This is to avoid a bug where ->handle_kicks() are missed when EVENT_IDX is enabled by default in userspace code. (mst: Rename to VHOST_SCSI_FEATURES + add comment) Acked-by: Michael S. Tsirkin Reviewed-by: Asias He Cc: Paolo Bonzini Signed-off-by: Nicholas Bellinger --- drivers/vhost/tcm_vhost.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index 43fb11ee2e8d..2968b4934659 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c @@ -60,6 +60,15 @@ enum { VHOST_SCSI_VQ_IO = 2, }; +/* + * VIRTIO_RING_F_EVENT_IDX seems broken. Not sure the bug is in + * kernel but disabling it helps. + * TODO: debug and remove the workaround. + */ +enum { + VHOST_SCSI_FEATURES = VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX) +}; + #define VHOST_SCSI_MAX_TARGET 256 #define VHOST_SCSI_MAX_VQ 128 @@ -946,7 +955,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs) static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) { - if (features & ~VHOST_FEATURES) + if (features & ~VHOST_SCSI_FEATURES) return -EOPNOTSUPP; mutex_lock(&vs->dev.mutex); @@ -992,7 +1001,7 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, return -EFAULT; return 0; case VHOST_GET_FEATURES: - features = VHOST_FEATURES; + features = VHOST_SCSI_FEATURES; if (copy_to_user(featurep, &features, sizeof features)) return -EFAULT; return 0; -- cgit v1.2.3 From f85eda8d75d37a3796cee7f5a906e50e3f13d9e1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 28 Mar 2013 23:06:00 -0700 Subject: target: Fix RESERVATION_CONFLICT status regression for iscsi-target special case This patch fixes a regression introduced in v3.8-rc1 code where a failed target_check_reservation() check in target_setup_cmd_from_cdb() was causing an incorrect SAM_STAT_GOOD status to be returned during a WRITE operation performed by an unregistered / unreserved iscsi initiator port. This regression is only effecting iscsi-target due to a special case check for TCM_RESERVATION_CONFLICT within iscsi_target_erl1.c:iscsit_execute_cmd(), and was still correctly disallowing WRITE commands from backend submission for unregistered / unreserved initiator ports, while returning the incorrect SAM_STAT_GOOD status due to the missing SAM_STAT_RESERVATION_CONFLICT assignment. This regression was first introduced with: commit de103c93aff0bed0ae984274e5dc8b95899badab Author: Christoph Hellwig Date: Tue Nov 6 12:24:09 2012 -0800 target: pass sense_reason as a return value Go ahead and re-add the missing SAM_STAT_RESERVATION_CONFLICT assignment during a target_check_reservation() failure, so that iscsi-target code sends the correct SCSI status. All other fabrics using target_submit_cmd_*() with a RESERVATION_CONFLICT call to transport_generic_request_failure() are not effected by this bug. Reported-by: Jeff Leung Cc: Christoph Hellwig Cc: Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2030b608136d..3243ea790eab 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1139,8 +1139,10 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) return ret; ret = target_check_reservation(cmd); - if (ret) + if (ret) { + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; return ret; + } ret = dev->transport->parse_cdb(cmd); if (ret) -- cgit v1.2.3 From 961b0fc840bf70511ef87d2f799eab014b4d2d37 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 29 Mar 2013 09:45:34 +0000 Subject: ASoC: wm0010: Constify usage of firmware filenames Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index ad2fee4bb4cd..55fdf0f4406c 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -342,7 +342,7 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len) data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i])); } -static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec) +static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) { struct spi_device *spi = to_spi_device(codec->dev); struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); -- cgit v1.2.3 From 3e112af51eedda46fe87d2cba427d48c4b7695fd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 29 Mar 2013 09:45:35 +0000 Subject: ASoC: wm0010: Report filename when we fail to load firmware Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 55fdf0f4406c..8df2b6e1a1a6 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -361,8 +361,8 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) ret = request_firmware(&fw, name, codec->dev); if (ret != 0) { - dev_err(codec->dev, "Failed to request application: %d\n", - ret); + dev_err(codec->dev, "Failed to request application(%s): %d\n", + name, ret); return ret; } -- cgit v1.2.3 From 939dc51bddc245df51c1e8ee44bf136621475149 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Mar 2013 13:03:39 +0800 Subject: ASoC: wm2000: Expose some more registers for diagnostics Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 4 +++- sound/soc/codecs/wm2000.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index f2ac38b61a1b..7fefd766b582 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -761,6 +761,8 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg) case WM2000_REG_SYS_CTL2: case WM2000_REG_ANC_STAT: case WM2000_REG_IF_CTL: + case WM2000_REG_ANA_MIC_CTL: + case WM2000_REG_SPK_CTL: return true; default: return false; @@ -771,7 +773,7 @@ static const struct regmap_config wm2000_regmap = { .reg_bits = 16, .val_bits = 8, - .max_register = WM2000_REG_IF_CTL, + .max_register = WM2000_REG_SPK_CTL, .readable_reg = wm2000_readable_reg, }; diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h index fb812cd9e77d..3870c0e1d246 100644 --- a/sound/soc/codecs/wm2000.h +++ b/sound/soc/codecs/wm2000.h @@ -30,6 +30,8 @@ #define WM2000_REG_SYS_CTL2 0xf004 #define WM2000_REG_ANC_STAT 0xf005 #define WM2000_REG_IF_CTL 0xf006 +#define WM2000_REG_ANA_MIC_CTL 0xf028 +#define WM2000_REG_SPK_CTL 0xf034 /* SPEECH_CLARITY */ #define WM2000_SPEECH_CLARITY 0x01 -- cgit v1.2.3 From 5b4617d82020addf244c8c5206270e49ef9933d6 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 28 Mar 2013 00:07:29 +0400 Subject: HID: fix Masterkit MA901 hid quirks This patch reverts commit 0322bd3980 ("usb hid quirks for Masterkit MA901 usb radio") and adds checks in hid_ignore() for Masterkit MA901 usb radio device. This usb radio device shares USB ID with many Atmel V-USB (and probably other) devices so patch sorts things out by checking name, vendor, product of hid device. Signed-off-by: Alexey Klimov Acked-by: Mauro Carvalho Chehab Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 13 ++++++++++++- drivers/hid/hid-ids.h | 5 ++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 512b01c04ea7..aa341d135867 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2077,7 +2077,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MASTERKIT, USB_DEVICE_ID_MASTERKIT_MA901RADIO) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, @@ -2244,6 +2243,18 @@ bool hid_ignore(struct hid_device *hdev) hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST)) return true; break; + case USB_VENDOR_ID_ATMEL_V_USB: + /* Masterkit MA901 usb radio based on Atmel tiny85 chip and + * it has the same USB ID as many Atmel V-USB devices. This + * usb radio is handled by radio-ma901.c driver so we want + * ignore the hid. Check the name, bus, product and ignore + * if we have MA901 usb radio. + */ + if (hdev->product == USB_DEVICE_ID_ATMEL_V_USB && + hdev->bus == BUS_USB && + strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0) + return true; + break; } if (hdev->type == HID_TYPE_USBMOUSE && diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c4388776f4e4..5309fd5eb0eb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -158,6 +158,8 @@ #define USB_VENDOR_ID_ATMEL 0x03eb #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c #define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118 +#define USB_VENDOR_ID_ATMEL_V_USB 0x16c0 +#define USB_DEVICE_ID_ATMEL_V_USB 0x05df #define USB_VENDOR_ID_AUREAL 0x0755 #define USB_DEVICE_ID_AUREAL_W01RN 0x2626 @@ -557,9 +559,6 @@ #define USB_VENDOR_ID_MADCATZ 0x0738 #define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540 -#define USB_VENDOR_ID_MASTERKIT 0x16c0 -#define USB_DEVICE_ID_MASTERKIT_MA901RADIO 0x05df - #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a -- cgit v1.2.3 From 30b29537bcba070b3df8d7d24c1975676a1a6a4f Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 28 Mar 2013 00:08:19 +0400 Subject: media: radio-ma901: return ENODEV in probe if usb_device doesn't match Masterkit MA901 usb radio device shares USB ID with Atmel V-USB devices. This patch adds additional checks in usb_ma901radio_probe() and if product or manufacturer doesn't match we return -ENODEV and don't continue. This allows hid drivers to handle not MA901 device. Signed-off-by: Alexey Klimov Acked-by: Mauro Carvalho Chehab Signed-off-by: Jiri Kosina --- drivers/media/radio/radio-ma901.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index c61f590029ad..348dafc0318a 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -347,9 +347,20 @@ static void usb_ma901radio_release(struct v4l2_device *v4l2_dev) static int usb_ma901radio_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct usb_device *dev = interface_to_usbdev(intf); struct ma901radio_device *radio; int retval = 0; + /* Masterkit MA901 usb radio has the same USB ID as many others + * Atmel V-USB devices. Let's make additional checks to be sure + * that this is our device. + */ + + if (dev->product && dev->manufacturer && + (strncmp(dev->product, "MA901", 5) != 0 + || strncmp(dev->manufacturer, "www.masterkit.ru", 16) != 0)) + return -ENODEV; + radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL); if (!radio) { dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n"); -- cgit v1.2.3 From d8fe29e9dea8d7d61fd140d8779326856478fc62 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 29 Mar 2013 08:09:34 -0600 Subject: Btrfs: don't drop path when printing out tree errors in scrub A user reported a panic where we were panicing somewhere in tree_backref_for_extent from scrub_print_warning. He only captured the trace but looking at scrub_print_warning we drop the path right before we mess with the extent buffer to print out a bunch of stuff, which isn't right. So fix this by dropping the path after we use the eb if we need to. Thanks, Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/scrub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 53c3501fa4ca..85e072b956d5 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -542,7 +542,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) eb = path->nodes[0]; ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); item_size = btrfs_item_size_nr(eb, path->slots[0]); - btrfs_release_path(path); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { do { @@ -558,7 +557,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) ret < 0 ? -1 : ref_level, ret < 0 ? -1 : ref_root); } while (ret != 1); + btrfs_release_path(path); } else { + btrfs_release_path(path); swarn.path = path; swarn.dev = dev; iterate_extent_inodes(fs_info, found_key.objectid, -- cgit v1.2.3 From 35e5cbc0af240778e61113286c019837e06aeec6 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 29 Mar 2013 15:39:16 +0100 Subject: reiserfs: Fix warning and inode leak when deleting inode with xattrs After commit 21d8a15a (lookup_one_len: don't accept . and ..) reiserfs started failing to delete xattrs from inode. This was due to a buggy test for '.' and '..' in fill_with_dentries() which resulted in passing '.' and '..' entries to lookup_one_len() in some cases. That returned error and so we failed to iterate over all xattrs of and inode. Fix the test in fill_with_dentries() along the lines of the one in lookup_one_len(). Reported-by: Pawel Zawora CC: stable@vger.kernel.org Signed-off-by: Jan Kara --- fs/reiserfs/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index c196369fe408..4cce1d9552fb 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -187,8 +187,8 @@ fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset, if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) return -ENOSPC; - if (name[0] == '.' && (name[1] == '\0' || - (name[1] == '.' && name[2] == '\0'))) + if (name[0] == '.' && (namelen < 2 || + (namelen == 2 && name[1] == '.'))) return 0; dentry = lookup_one_len(name, dbuf->xadir, namelen); -- cgit v1.2.3 From dd84f9259bfe8454ee7c9e6faf6ac13f45bb1ed2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 8 Mar 2013 15:25:58 +0800 Subject: ASoC: wm_adsp: Provide defines for firmwares For future work to have specific handling for some firmwares. Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index febb4c76535e..68eda929fbde 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -193,17 +193,25 @@ static void wm_adsp_buf_free(struct list_head *list) #define WM_ADSP_NUM_FW 4 +#define WM_ADSP_FW_MBC_VSS 0 +#define WM_ADSP_FW_TX 1 +#define WM_ADSP_FW_TX_SPK 2 +#define WM_ADSP_FW_RX_ANC 3 + static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { - "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC" + [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", + [WM_ADSP_FW_TX] = "Tx", + [WM_ADSP_FW_TX_SPK] = "Tx Speaker", + [WM_ADSP_FW_RX_ANC] = "Rx ANC", }; static struct { const char *file; } wm_adsp_fw[WM_ADSP_NUM_FW] = { - { .file = "mbc-vss" }, - { .file = "tx" }, - { .file = "tx-spk" }, - { .file = "rx-anc" }, + [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, + [WM_ADSP_FW_TX] = { .file = "tx" }, + [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, + [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, }; static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From b6ed61cfa24786e36164869b593d44d411a700ad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Mar 2013 18:00:24 +0000 Subject: ASoC: wm_adsp: Split ADSP1 and ADSP2 firmware controls Now that we have regular register mapped controls we should be splitting the control sets for ADSP1 and ADSP2 as the register maps are not identical. Do that. Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm_adsp.c | 26 +++++++++++++++++++------- sound/soc/codecs/wm_adsp.h | 3 ++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index ddc98f02ecbd..57ba315d0c84 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec) return ret; } - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); + ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2); if (ret != 0) return ret; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index d1b43ebec087..cb03cc448da6 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1572,7 +1572,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) if (ret != 0) return ret; - ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2); + ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 3a481fd1bf9a..bc03baef39fa 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -247,7 +247,18 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; -static const struct soc_enum wm_adsp_rate_enum[] = { +const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { + SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], + wm_adsp_fw_get, wm_adsp_fw_put), +}; +EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); + +#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) +static const struct soc_enum wm_adsp2_rate_enum[] = { SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, ARIZONA_DSP1_RATE_SHIFT, 0xf, ARIZONA_RATE_ENUM_SIZE, @@ -266,21 +277,22 @@ static const struct soc_enum wm_adsp_rate_enum[] = { arizona_rate_text, arizona_rate_val), }; -const struct snd_kcontrol_new wm_adsp_fw_controls[] = { +const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP1 Rate", wm_adsp_rate_enum[0]), + SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP2 Rate", wm_adsp_rate_enum[1]), + SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP3 Rate", wm_adsp_rate_enum[2]), + SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP4 Rate", wm_adsp_rate_enum[3]), + SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), }; -EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); +EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); +#endif static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, int type) diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index cb8871a3ec00..9f90c9fea842 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -65,7 +65,8 @@ struct wm_adsp { .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } -extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; +extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; int wm_adsp1_init(struct wm_adsp *adsp); int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); -- cgit v1.2.3 From ed176886b68fbc450ddbe808684a142fcad72b56 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 29 Mar 2013 11:02:30 -0700 Subject: ia64 idle: delete stale (*idle)() function pointer Commit 3e7fc708eb41 ("ia64 idle: delete pm_idle") in 3.9-rc1 didn't finish the job, leaving an un-initialized reference to (*idle)(). [ Haven't seen a crash from this - but seems like we are just being lucky that "idle" is zero so it does get initialized before we jump to randomland - Len ] Reported-by: Lars-Peter Clausen Signed-off-by: Len Brown Signed-off-by: Tony Luck Signed-off-by: Linus Torvalds --- arch/ia64/kernel/process.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index e34f565f595a..6f7dc8b7b35c 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -291,7 +291,6 @@ cpu_idle (void) } if (!need_resched()) { - void (*idle)(void); #ifdef CONFIG_SMP min_xtp(); #endif @@ -299,9 +298,7 @@ cpu_idle (void) if (mark_idle) (*mark_idle)(1); - if (!idle) - idle = default_idle; - (*idle)(); + default_idle(); if (mark_idle) (*mark_idle)(0); #ifdef CONFIG_SMP -- cgit v1.2.3 From 6e2a4505dba0cae8faa701426185dfb7b49f537c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 27 Mar 2013 09:16:30 -0500 Subject: rbd: don't zero-fill non-image object requests A result of ENOENT from a read request for an object that's part of an rbd image indicates that there is a hole in that portion of the image. Similarly, a short read for such an object indicates that the remainder of the read should be interpreted a full read with zeros filling out the end of the request. This behavior is not correct for objects that are not backing rbd image data. Currently rbd_img_obj_request_callback() assumes it should be done for all objects. Change rbd_img_obj_request_callback() so it only does this zeroing for image objects. Encapsulate that special handling in its own function. Add an assertion that the image object request is a bio request, since we assume that (and we currently don't support any other types). This resolves a problem identified here: http://tracker.ceph.com/issues/4559 The regression was introduced by bf0d5f503dc11d6314c0503591d258d60ee9c944. Reported-by: Dan van der Ster Signed-off-by: Alex Elder Reviewed-off-by: Sage Weil --- drivers/block/rbd.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 6c81a4c040b9..f556f8a8b3f9 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1264,6 +1264,32 @@ static bool obj_request_done_test(struct rbd_obj_request *obj_request) return atomic_read(&obj_request->done) != 0; } +static void +rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) +{ + dout("%s: obj %p img %p result %d %llu/%llu\n", __func__, + obj_request, obj_request->img_request, obj_request->result, + obj_request->xferred, obj_request->length); + /* + * ENOENT means a hole in the image. We zero-fill the + * entire length of the request. A short read also implies + * zero-fill to the end of the request. Either way we + * update the xferred count to indicate the whole request + * was satisfied. + */ + BUG_ON(obj_request->type != OBJ_REQUEST_BIO); + if (obj_request->result == -ENOENT) { + zero_bio_chain(obj_request->bio_list, 0); + obj_request->result = 0; + obj_request->xferred = obj_request->length; + } else if (obj_request->xferred < obj_request->length && + !obj_request->result) { + zero_bio_chain(obj_request->bio_list, obj_request->xferred); + obj_request->xferred = obj_request->length; + } + obj_request_done_set(obj_request); +} + static void rbd_obj_request_complete(struct rbd_obj_request *obj_request) { dout("%s: obj %p cb %p\n", __func__, obj_request, @@ -1284,23 +1310,10 @@ static void rbd_osd_read_callback(struct rbd_obj_request *obj_request) { dout("%s: obj %p result %d %llu/%llu\n", __func__, obj_request, obj_request->result, obj_request->xferred, obj_request->length); - /* - * ENOENT means a hole in the object. We zero-fill the - * entire length of the request. A short read also implies - * zero-fill to the end of the request. Either way we - * update the xferred count to indicate the whole request - * was satisfied. - */ - if (obj_request->result == -ENOENT) { - zero_bio_chain(obj_request->bio_list, 0); - obj_request->result = 0; - obj_request->xferred = obj_request->length; - } else if (obj_request->xferred < obj_request->length && - !obj_request->result) { - zero_bio_chain(obj_request->bio_list, obj_request->xferred); - obj_request->xferred = obj_request->length; - } - obj_request_done_set(obj_request); + if (obj_request->img_request) + rbd_img_obj_request_read_callback(obj_request); + else + obj_request_done_set(obj_request); } static void rbd_osd_write_callback(struct rbd_obj_request *obj_request) -- cgit v1.2.3 From 9cfe8b156c21cf340b3a10ecb3022fbbc1c39185 Mon Sep 17 00:00:00 2001 From: Mirko Lindner Date: Tue, 26 Mar 2013 06:38:35 +0000 Subject: sky2: Receive Overflows not counted The sky2 driver doesn't count the Receive Overflows because the MAC interrupt for this event is not set in the MAC's interrupt mask. The MAC's interrupt mask is set only for Transmit FIFO Underruns. Fix: The correct setting should be (GM_IS_TX_FF_UR | GM_IS_RX_FF_OR) Otherwise the Receive Overflow event will not generate any interrupt. The Receive Overflow interrupt is handled correctly Signed-off-by: Mirko Lindner Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h index 615ac63ea860..ec6dcd80152b 100644 --- a/drivers/net/ethernet/marvell/sky2.h +++ b/drivers/net/ethernet/marvell/sky2.h @@ -2074,7 +2074,7 @@ enum { GM_IS_RX_FF_OR = 1<<1, /* Receive FIFO Overrun */ GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */ -#define GMAC_DEF_MSK GM_IS_TX_FF_UR +#define GMAC_DEF_MSK (GM_IS_TX_FF_UR | GM_IS_RX_FF_OR) }; /* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ -- cgit v1.2.3 From 74f9f42c1c1650e74fb464f76644c9041f996851 Mon Sep 17 00:00:00 2001 From: Mirko Lindner Date: Tue, 26 Mar 2013 06:38:42 +0000 Subject: sky2: Threshold for Pause Packet is set wrong The sky2 driver sets the Rx Upper Threshold for Pause Packet generation to a wrong value which leads to only 2kB of RAM remaining space. This can lead to Rx overflow errors even with activated flow-control. Fix: We should increase the value to 8192/8 Signed-off-by: Mirko Lindner Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index fc07ca35721b..6a0e671fcecd 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1067,7 +1067,7 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space) sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp); sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2); - tp = space - 2048/8; + tp = space - 8192/8; sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp); sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4); } else { -- cgit v1.2.3 From 1c4a154e5253687c51123956dfcee9e9dfa8542d Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Tue, 26 Mar 2013 08:13:34 +0000 Subject: ipv6: don't accept node local multicast traffic from the wire Erik Hugne's errata proposal (Errata ID: 3480) to RFC4291 has been verified: http://www.rfc-editor.org/errata_search.php?eid=3480 We have to check for pkt_type and loopback flag because either the packets are allowed to travel over the loopback interface (in which case pkt_type is PACKET_HOST and IFF_LOOPBACK flag is set) or they travel over a non-loopback interface back to us (in which case PACKET_TYPE is PACKET_LOOPBACK and IFF_LOOPBACK flag is not set). Cc: Erik Hugne Cc: YOSHIFUJI Hideaki Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/ip6_input.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index e33fe0ab2568..2bab2aa59745 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -118,6 +118,18 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ipv6_addr_loopback(&hdr->daddr)) goto err; + /* RFC4291 Errata ID: 3480 + * Interface-Local scope spans only a single interface on a + * node and is useful only for loopback transmission of + * multicast. Packets with interface-local scope received + * from another node must be discarded. + */ + if (!(skb->pkt_type == PACKET_LOOPBACK || + dev->flags & IFF_LOOPBACK) && + ipv6_addr_is_multicast(&hdr->daddr) && + IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) + goto err; + /* RFC4291 2.7 * Nodes must not originate a packet to a multicast address whose scope * field contains the reserved value 0; if such a packet is received, it -- cgit v1.2.3 From 1bc7db16782c2a581fb4d53ca853631050f31611 Mon Sep 17 00:00:00 2001 From: "nikolay@redhat.com" Date: Wed, 27 Mar 2013 03:32:41 +0000 Subject: bonding: fix disabling of arp_interval and miimon Currently if either arp_interval or miimon is disabled, they both get disabled, and upon disabling they get executed once more which is not the proper behaviour. Also when doing a no-op and disabling an already disabled one, the other again gets disabled. Also fix the error messages with the proper valid ranges, and a small typo fix in the up delay error message (outputting "down delay", instead of "up delay"). Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_sysfs.c | 92 +++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index db103e03ba05..ea7a388f4843 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -527,7 +527,7 @@ static ssize_t bonding_store_arp_interval(struct device *d, goto out; } if (new_value < 0) { - pr_err("%s: Invalid arp_interval value %d not in range 1-%d; rejected.\n", + pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n", bond->dev->name, new_value, INT_MAX); ret = -EINVAL; goto out; @@ -542,14 +542,15 @@ static ssize_t bonding_store_arp_interval(struct device *d, pr_info("%s: Setting ARP monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.arp_interval = new_value; - if (bond->params.miimon) { - pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", - bond->dev->name, bond->dev->name); - bond->params.miimon = 0; - } - if (!bond->params.arp_targets[0]) { - pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", - bond->dev->name); + if (new_value) { + if (bond->params.miimon) { + pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", + bond->dev->name, bond->dev->name); + bond->params.miimon = 0; + } + if (!bond->params.arp_targets[0]) + pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", + bond->dev->name); } if (bond->dev->flags & IFF_UP) { /* If the interface is up, we may need to fire off @@ -557,10 +558,13 @@ static ssize_t bonding_store_arp_interval(struct device *d, * timer will get fired off when the open function * is called. */ - cancel_delayed_work_sync(&bond->mii_work); - queue_delayed_work(bond->wq, &bond->arp_work, 0); + if (!new_value) { + cancel_delayed_work_sync(&bond->arp_work); + } else { + cancel_delayed_work_sync(&bond->mii_work); + queue_delayed_work(bond->wq, &bond->arp_work, 0); + } } - out: rtnl_unlock(); return ret; @@ -702,7 +706,7 @@ static ssize_t bonding_store_downdelay(struct device *d, } if (new_value < 0) { pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 1, INT_MAX); + bond->dev->name, new_value, 0, INT_MAX); ret = -EINVAL; goto out; } else { @@ -757,8 +761,8 @@ static ssize_t bonding_store_updelay(struct device *d, goto out; } if (new_value < 0) { - pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 1, INT_MAX); + pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", + bond->dev->name, new_value, 0, INT_MAX); ret = -EINVAL; goto out; } else { @@ -968,37 +972,37 @@ static ssize_t bonding_store_miimon(struct device *d, } if (new_value < 0) { pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", - bond->dev->name, new_value, 1, INT_MAX); + bond->dev->name, new_value, 0, INT_MAX); ret = -EINVAL; goto out; - } else { - pr_info("%s: Setting MII monitoring interval to %d.\n", - bond->dev->name, new_value); - bond->params.miimon = new_value; - if (bond->params.updelay) - pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", - bond->dev->name, - bond->params.updelay * bond->params.miimon); - if (bond->params.downdelay) - pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); - if (bond->params.arp_interval) { - pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", - bond->dev->name); - bond->params.arp_interval = 0; - if (bond->params.arp_validate) { - bond->params.arp_validate = - BOND_ARP_VALIDATE_NONE; - } - } - - if (bond->dev->flags & IFF_UP) { - /* If the interface is up, we may need to fire off - * the MII timer. If the interface is down, the - * timer will get fired off when the open function - * is called. - */ + } + pr_info("%s: Setting MII monitoring interval to %d.\n", + bond->dev->name, new_value); + bond->params.miimon = new_value; + if (bond->params.updelay) + pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", + bond->dev->name, + bond->params.updelay * bond->params.miimon); + if (bond->params.downdelay) + pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); + if (new_value && bond->params.arp_interval) { + pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", + bond->dev->name); + bond->params.arp_interval = 0; + if (bond->params.arp_validate) + bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; + } + if (bond->dev->flags & IFF_UP) { + /* If the interface is up, we may need to fire off + * the MII timer. If the interface is down, the + * timer will get fired off when the open function + * is called. + */ + if (!new_value) { + cancel_delayed_work_sync(&bond->mii_work); + } else { cancel_delayed_work_sync(&bond->arp_work); queue_delayed_work(bond->wq, &bond->mii_work, 0); } -- cgit v1.2.3 From ff7f3efb9abf986f4ecd8793a9593f7ca4d6431a Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 29 Mar 2013 13:50:21 -0400 Subject: tile: expect new initramfs name from hypervisor file system The current Tilera boot infrastructure now provides the initramfs to Linux as a Tilera-hypervisor file named "initramfs", rather than "initramfs.cpio.gz", as before. (This makes it reasonable to use other compression techniques than gzip on the file without having to worry about the name causing confusion.) Adapt to use the new name, but also fall back to checking for the old name. Cc'ing to stable so that older kernels will remain compatible with newer Tilera boot infrastructure. Signed-off-by: Chris Metcalf Cc: stable@vger.kernel.org --- arch/tile/kernel/setup.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index d1e15f7b59c6..7a5aa1a7864e 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -1004,15 +1004,8 @@ void __cpuinit setup_cpu(int boot) #ifdef CONFIG_BLK_DEV_INITRD -/* - * Note that the kernel can potentially support other compression - * techniques than gz, though we don't do so by default. If we ever - * decide to do so we can either look for other filename extensions, - * or just allow a file with this name to be compressed with an - * arbitrary compressor (somewhat counterintuitively). - */ static int __initdata set_initramfs_file; -static char __initdata initramfs_file[128] = "initramfs.cpio.gz"; +static char __initdata initramfs_file[128] = "initramfs"; static int __init setup_initramfs_file(char *str) { @@ -1026,9 +1019,9 @@ static int __init setup_initramfs_file(char *str) early_param("initramfs_file", setup_initramfs_file); /* - * We look for an "initramfs.cpio.gz" file in the hvfs. - * If there is one, we allocate some memory for it and it will be - * unpacked to the initramfs. + * We look for a file called "initramfs" in the hvfs. If there is one, we + * allocate some memory for it and it will be unpacked to the initramfs. + * If it's compressed, the initd code will uncompress it first. */ static void __init load_hv_initrd(void) { @@ -1038,10 +1031,16 @@ static void __init load_hv_initrd(void) fd = hv_fs_findfile((HV_VirtAddr) initramfs_file); if (fd == HV_ENOENT) { - if (set_initramfs_file) + if (set_initramfs_file) { pr_warning("No such hvfs initramfs file '%s'\n", initramfs_file); - return; + return; + } else { + /* Try old backwards-compatible name. */ + fd = hv_fs_findfile((HV_VirtAddr)"initramfs.cpio.gz"); + if (fd == HV_ENOENT) + return; + } } BUG_ON(fd < 0); stat = hv_fs_fstat(fd); -- cgit v1.2.3 From 50eab0503a7579ada512e4968738b7c9737cf36e Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Wed, 27 Mar 2013 23:42:41 +0000 Subject: net: fix the use of this_cpu_ptr flush_tasklet is not percpu var, and percpu is percpu var, and this_cpu_ptr(&info->cache->percpu->flush_tasklet) is not equal to &this_cpu_ptr(info->cache->percpu)->flush_tasklet 1f743b076(use this_cpu_ptr per-cpu helper) introduced this bug. Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/core/flow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/flow.c b/net/core/flow.c index c56ea6f7f6c7..2bfd081c59f7 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -328,7 +328,7 @@ static void flow_cache_flush_per_cpu(void *data) struct flow_flush_info *info = data; struct tasklet_struct *tasklet; - tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet); + tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet; tasklet->data = (unsigned long)info; tasklet_schedule(tasklet); } -- cgit v1.2.3 From 4c51e53689569398d656e631c17308d9b8e84650 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 28 Mar 2013 02:34:41 +0000 Subject: smsc75xx: fix jumbo frame support This patch enables RX of jumbo frames for LAN7500. Previously the driver would transmit jumbo frames succesfully but would drop received jumbo frames (incrementing the interface errors count). With this patch applied the device can succesfully receive jumbo frames up to MTU 9000 (9014 bytes on the wire including ethernet header). Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc75xx.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 9abe51710f22..1a15ec14c386 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -914,8 +914,12 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size) static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) { struct usbnet *dev = netdev_priv(netdev); + int ret; + + if (new_mtu > MAX_SINGLE_PACKET_SIZE) + return -EINVAL; - int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu); + ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN); if (ret < 0) { netdev_warn(dev->net, "Failed to set mac rx frame length\n"); return ret; @@ -1324,7 +1328,7 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf); - ret = smsc75xx_set_rx_max_frame_length(dev, 1514); + ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN); if (ret < 0) { netdev_warn(dev->net, "Failed to set max rx frame length\n"); return ret; @@ -2134,8 +2138,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT)) dev->net->stats.rx_frame_errors++; } else { - /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ - if (unlikely(size > (ETH_FRAME_LEN + 12))) { + /* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */ + if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) { netif_dbg(dev, rx_err, dev->net, "size err rx_cmd_a=0x%08x\n", rx_cmd_a); -- cgit v1.2.3 From a561cf7edf9863198bfccecfc5cfe26d951ebd20 Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Wed, 27 Mar 2013 23:13:26 +0000 Subject: net: core: Remove redundant call to 'nf_reset' in 'dev_forward_skb' 'nf_reset' is called just prior calling 'netif_rx'. No need to call it twice. Reported-by: Igor Michailov Signed-off-by: Shmulik Ladkani Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index b13e5c766c11..6591440cc03d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1624,7 +1624,6 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) } skb_orphan(skb); - nf_reset(skb); if (unlikely(!is_skb_forwardable(dev, skb))) { atomic_long_inc(&dev->rx_dropped); -- cgit v1.2.3 From dc574f1d52d893f516f3786ff7635450bac00eef Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Mar 2013 11:32:44 +0000 Subject: net: calxedaxgmac: fix rx ring handling when OOM If skb allocation for the rx ring fails repeatedly, we can reach a point were the ring is empty. In this condition, the driver is out of sync with the h/w. While this has always been possible, the removal of the skb recycling seems to have made triggering this problem easier. Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/ethernet/calxeda/xgmac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index a170065b5973..bb1e80bfa78a 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -1141,6 +1141,9 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit) struct sk_buff *skb; int frame_len; + if (!dma_ring_cnt(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ)) + break; + entry = priv->rx_tail; p = priv->dma_rx + entry; if (desc_get_owner(p)) -- cgit v1.2.3 From e6c3827dcfe53dd78b824d2ee4007a216ada739e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Mar 2013 11:32:45 +0000 Subject: net: calxedaxgmac: Wake-on-LAN fixes WOL is broken because the magic packet status bit is getting set rather than the enable bit. The PMT interrupt is not getting serviced because the PMT interrupt is also enabled on the global interrupt, but not cleared by the global interrupt and the global interrupt is higher priority. This fixes both of these issues to get WOL working. There's still a problem with receive after resume, but at least now we can wake-up. Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/ethernet/calxeda/xgmac.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index bb1e80bfa78a..b0ebc9f6d55e 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -163,6 +163,7 @@ #define XGMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */ /* XGMAC_INT_STAT reg */ +#define XGMAC_INT_STAT_PMTIM 0x00800000 /* PMT Interrupt Mask */ #define XGMAC_INT_STAT_PMT 0x0080 /* PMT Interrupt Status */ #define XGMAC_INT_STAT_LPI 0x0040 /* LPI Interrupt Status */ @@ -960,6 +961,9 @@ static int xgmac_hw_init(struct net_device *dev) writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS); writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA); + /* Mask power mgt interrupt */ + writel(XGMAC_INT_STAT_PMTIM, ioaddr + XGMAC_INT_STAT); + /* XGMAC requires AXI bus init. This is a 'magic number' for now */ writel(0x0077000E, ioaddr + XGMAC_DMA_AXI_BUS); @@ -1828,7 +1832,7 @@ static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode) unsigned int pmt = 0; if (mode & WAKE_MAGIC) - pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT; + pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT_EN; if (mode & WAKE_UCAST) pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_GLBL_UNICAST; -- cgit v1.2.3 From cd68ddd4c29ab523440299f24ff2417fe7a0dca6 Mon Sep 17 00:00:00 2001 From: Vijay Subramanian Date: Thu, 28 Mar 2013 13:52:00 +0000 Subject: net: fq_codel: Fix off-by-one error Currently, we hold a max of sch->limit -1 number of packets instead of sch->limit packets. Fix this off-by-one error. Signed-off-by: Vijay Subramanian Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_fq_codel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 4e606fcb2534..55786283a3df 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -195,7 +195,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) flow->deficit = q->quantum; flow->dropped = 0; } - if (++sch->q.qlen < sch->limit) + if (++sch->q.qlen <= sch->limit) return NET_XMIT_SUCCESS; q->drop_overlimit++; -- cgit v1.2.3 From 188ab1b105c96656f6bcfb49d0d8bb1b1936b632 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 28 Mar 2013 18:10:50 +0000 Subject: atl1e: drop pci-msi support because of packet corruption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of pci-msi results in corrupted dma packet transfers to the host. Reported-by: rebelyouth Cc: Huang, Xiong Tested-by: Christian Sünkenberg Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atl1e/atl1e.h | 1 - drivers/net/ethernet/atheros/atl1e/atl1e_main.c | 19 ++----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h index 829b5ad71d0d..edfdf6b950e7 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e.h +++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h @@ -438,7 +438,6 @@ struct atl1e_adapter { struct atl1e_hw hw; struct atl1e_hw_stats hw_stats; - bool have_msi; u32 wol; u16 link_speed; u16 link_duplex; diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 92f4734f860d..f73d5609439a 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -1849,34 +1849,19 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter) struct net_device *netdev = adapter->netdev; free_irq(adapter->pdev->irq, netdev); - - if (adapter->have_msi) - pci_disable_msi(adapter->pdev); } static int atl1e_request_irq(struct atl1e_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; - int flags = 0; int err = 0; - adapter->have_msi = true; - err = pci_enable_msi(pdev); - if (err) { - netdev_dbg(netdev, - "Unable to allocate MSI interrupt Error: %d\n", err); - adapter->have_msi = false; - } - - if (!adapter->have_msi) - flags |= IRQF_SHARED; - err = request_irq(pdev->irq, atl1e_intr, flags, netdev->name, netdev); + err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name, + netdev); if (err) { netdev_dbg(adapter->netdev, "Unable to allocate interrupt Error: %d\n", err); - if (adapter->have_msi) - pci_disable_msi(pdev); return err; } netdev_dbg(netdev, "atl1e_request_irq OK\n"); -- cgit v1.2.3 From 8622315e0142eba78ec0a8075b5a6fd481a059a4 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Thu, 28 Mar 2013 23:54:08 +0000 Subject: MAINTAINERS: Update netxen_nic maintainers list o Add myself to netxen_nic maintainers list Signed-off-by: Manish Chopra Signed-off-by: David S. Miller --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 457ff5c52396..6e6d606e13dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5562,6 +5562,7 @@ F: include/uapi/linux/if_* F: include/uapi/linux/netdevice.h NETXEN (1/10) GbE SUPPORT +M: Manish Chopra M: Sony Chacko M: Rajesh Borundia L: netdev@vger.kernel.org -- cgit v1.2.3 From 00cfec37484761a44a3b6f4675a54caa618210ae Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Mar 2013 03:01:22 +0000 Subject: net: add a synchronize_net() in netdev_rx_handler_unregister() commit 35d48903e97819 (bonding: fix rx_handler locking) added a race in bonding driver, reported by Steven Rostedt who did a very good diagnosis : I'm currently debugging a crash in an old 3.0-rt kernel that one of our customers is seeing. The bug happens with a stress test that loads and unloads the bonding module in a loop (I don't know all the details as I'm not the one that is directly interacting with the customer). But the bug looks to be something that may still be present and possibly present in mainline too. It will just be much harder to trigger it in mainline. In -rt, interrupts are threads, and can schedule in and out just like any other thread. Note, mainline now supports interrupt threads so this may be easily reproducible in mainline as well. I don't have the ability to tell the customer to try mainline or other kernels, so my hands are somewhat tied to what I can do. But according to a core dump, I tracked down that the eth irq thread crashed in bond_handle_frame() here: slave = bond_slave_get_rcu(skb->dev); bond = slave->bond; <--- BUG the slave returned was NULL and accessing slave->bond caused a NULL pointer dereference. Looking at the code that unregisters the handler: void netdev_rx_handler_unregister(struct net_device *dev) { ASSERT_RTNL(); RCU_INIT_POINTER(dev->rx_handler, NULL); RCU_INIT_POINTER(dev->rx_handler_data, NULL); } Which is basically: dev->rx_handler = NULL; dev->rx_handler_data = NULL; And looking at __netif_receive_skb() we have: rx_handler = rcu_dereference(skb->dev->rx_handler); if (rx_handler) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = NULL; } switch (rx_handler(&skb)) { My question to all of you is, what stops this interrupt from happening while the bonding module is unloading? What happens if the interrupt triggers and we have this: CPU0 CPU1 ---- ---- rx_handler = skb->dev->rx_handler netdev_rx_handler_unregister() { dev->rx_handler = NULL; dev->rx_handler_data = NULL; rx_handler() bond_handle_frame() { slave = skb->dev->rx_handler; bond = slave->bond; <-- NULL pointer dereference!!! What protection am I missing in the bond release handler that would prevent the above from happening? We can fix bug this in two ways. First is adding a test in bond_handle_frame() and others to check if rx_handler_data is NULL. A second way is adding a synchronize_net() in netdev_rx_handler_unregister() to make sure that a rcu protected reader has the guarantee to see a non NULL rx_handler_data. The second way is better as it avoids an extra test in fast path. Reported-by: Steven Rostedt Signed-off-by: Eric Dumazet Cc: Jiri Pirko Cc: Paul E. McKenney Acked-by: Steven Rostedt Reviewed-by: Paul E. McKenney Signed-off-by: David S. Miller --- net/core/dev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 6591440cc03d..13e6447f0398 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3313,6 +3313,7 @@ int netdev_rx_handler_register(struct net_device *dev, if (dev->rx_handler) return -EBUSY; + /* Note: rx_handler_data must be set before rx_handler */ rcu_assign_pointer(dev->rx_handler_data, rx_handler_data); rcu_assign_pointer(dev->rx_handler, rx_handler); @@ -3333,6 +3334,11 @@ void netdev_rx_handler_unregister(struct net_device *dev) ASSERT_RTNL(); RCU_INIT_POINTER(dev->rx_handler, NULL); + /* a reader seeing a non NULL rx_handler in a rcu_read_lock() + * section has a guarantee to see a non NULL rx_handler_data + * as well. + */ + synchronize_net(); RCU_INIT_POINTER(dev->rx_handler_data, NULL); } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); -- cgit v1.2.3 From 14bc435ea54cb888409efb54fc6b76c13ef530e9 Mon Sep 17 00:00:00 2001 From: "Max.Nekludov@us.elster.com" Date: Fri, 29 Mar 2013 05:27:36 +0000 Subject: ks8851: Fix interpretation of rxlen field. According to the Datasheet (page 52): 15-12 Reserved 11-0 RXBC Receive Byte Count This field indicates the present received frame byte size. The code has a bug: rxh = ks8851_rdreg32(ks, KS_RXFHSR); rxstat = rxh & 0xffff; rxlen = rxh >> 16; // BUG!!! 0xFFF mask should be applied Signed-off-by: Max Nekludov Signed-off-by: David S. Miller --- drivers/net/ethernet/micrel/ks8851.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 33bcb63d56a2..8fb481252e2c 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -528,7 +528,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks) for (; rxfc != 0; rxfc--) { rxh = ks8851_rdreg32(ks, KS_RXFHSR); rxstat = rxh & 0xffff; - rxlen = rxh >> 16; + rxlen = (rxh >> 16) & 0xfff; netif_dbg(ks, rx_status, ks->netdev, "rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen); -- cgit v1.2.3 From 0cd5751ab360573f607d1cbf97aa072667f888c8 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 29 Mar 2013 23:41:42 +0530 Subject: ASoC: mid-x86 - add support for meaadata apis while at it, update the copyright timeline too Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/mid-x86/sst_platform.c | 12 +++++++++++- sound/soc/mid-x86/sst_platform.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index a263cbed8624..968656ceb39e 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -1,7 +1,7 @@ /* * sst_platform.c - Intel MID Platform driver * - * Copyright (C) 2010-2012 Intel Corp + * Copyright (C) 2010-2013 Intel Corp * Author: Vinod Koul * Author: Harsha Priya * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -652,11 +652,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, return stream->compr_ops->get_codec_caps(codec); } +static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->set_metadata(stream->id, metadata); +} + static struct snd_compr_ops sst_platform_compr_ops = { .open = sst_platform_compr_open, .free = sst_platform_compr_free, .set_params = sst_platform_compr_set_params, + .set_metadata = sst_platform_compr_set_metadata, .trigger = sst_platform_compr_trigger, .pointer = sst_platform_compr_pointer, .ack = sst_platform_compr_ack, diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h index d61c5d514ffa..cacc9066ec52 100644 --- a/sound/soc/mid-x86/sst_platform.h +++ b/sound/soc/mid-x86/sst_platform.h @@ -124,6 +124,8 @@ struct compress_sst_ops { int (*close) (unsigned int str_id); int (*get_caps) (struct snd_compr_caps *caps); int (*get_codec_caps) (struct snd_compr_codec_caps *codec); + int (*set_metadata) (unsigned int str_id, + struct snd_compr_metadata *mdata); }; -- cgit v1.2.3 From 46a1f21a679abaaeae6db9969963dc998c9f1c1c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Mar 2013 22:59:53 +0100 Subject: PNP: List Rafael Wysocki as a maintainer The Adam Belay's e-mail address in MAINTAINERS under PNP SUPPORT is not valid any more and I started to maintain that code in the meantime as a matter of fact, so list myself as a maintainer of it along with Bjorn and remove the Adam's entry from it. Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 44135e3d7410..60a45838893f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6209,7 +6209,7 @@ F: include/linux/power_supply.h F: drivers/power/ PNP SUPPORT -M: Adam Belay +M: Rafael J. Wysocki M: Bjorn Helgaas S: Maintained F: drivers/pnp/ -- cgit v1.2.3 From f73bb9b35596e045feacdf4d2fd32cfb087e2411 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 3 Mar 2013 20:51:28 +0000 Subject: dmaengine: dw_dma: fix endianess for DT xlate function As reported by Wu Fengguang's build robot tracking sparse warnings, the dma_spec arguments in the dw_dma_xlate are already byte swapped on little-endian platforms and must not get swapped again. This code is currently not used anywhere, but will be used in Linux 3.10 when the ARM SPEAr platform starts using the generic DMA DT binding. Signed-off-by: Arnd Bergmann Reported-by: Fengguang Wu Acked-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index c599558faeda..eb81ec9d5b91 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1276,9 +1276,9 @@ static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec, if (dma_spec->args_count != 3) return NULL; - fargs.req = be32_to_cpup(dma_spec->args+0); - fargs.src = be32_to_cpup(dma_spec->args+1); - fargs.dst = be32_to_cpup(dma_spec->args+2); + fargs.req = dma_spec->args[0]; + fargs.src = dma_spec->args[1]; + fargs.dst = dma_spec->args[2]; if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS || fargs.src >= dw->nr_masters || -- cgit v1.2.3 From bce95c63ef1bcf528ea45c41505eb4c21560d92d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Feb 2013 13:52:17 +0200 Subject: dw_dmac: adjust slave_id accordingly to request line base On some hardware configurations we have got the request line with the offset. The patch introduces convert_slave_id() helper for that cases. The request line base is came from the driver data provided by the platform_device_id table. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Cc: Viresh Kumar Acked-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 17 ++++++++++++++++- drivers/dma/dw_dmac_regs.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index eb81ec9d5b91..43a5329d4483 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1001,6 +1001,13 @@ static inline void convert_burst(u32 *maxburst) *maxburst = 0; } +static inline void convert_slave_id(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + + dwc->dma_sconfig.slave_id -= dw->request_line_base; +} + static int set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { @@ -1015,6 +1022,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) convert_burst(&dwc->dma_sconfig.src_maxburst); convert_burst(&dwc->dma_sconfig.dst_maxburst); + convert_slave_id(dwc); return 0; } @@ -1628,6 +1636,7 @@ dw_dma_parse_dt(struct platform_device *pdev) static int dw_probe(struct platform_device *pdev) { + const struct platform_device_id *match; struct dw_dma_platform_data *pdata; struct resource *io; struct dw_dma *dw; @@ -1711,6 +1720,11 @@ static int dw_probe(struct platform_device *pdev) memcpy(dw->data_width, pdata->data_width, 4); } + /* Get the base request line if set */ + match = platform_get_device_id(pdev); + if (match) + dw->request_line_base = (unsigned int)match->driver_data; + /* Calculate all channel mask before DMA setup */ dw->all_chan_mask = (1 << nr_channels) - 1; @@ -1906,7 +1920,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table); #endif static const struct platform_device_id dw_dma_ids[] = { - { "INTL9C60", 0 }, + /* Name, Request Line Base */ + { "INTL9C60", (kernel_ulong_t)16 }, { } }; diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index cf0ce5c77d60..4d02c3669b75 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -247,6 +247,7 @@ struct dw_dma { /* hardware configuration */ unsigned char nr_masters; unsigned char data_width[4]; + unsigned int request_line_base; struct dw_dma_chan chan[0]; }; -- cgit v1.2.3 From 165b1b8bbc17c9469b053bab78b11b7cbce6d161 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Fri, 29 Mar 2013 16:30:07 +0530 Subject: virtio: console: rename cvq_lock to c_ivq_lock The cvq_lock was taken for the c_ivq. Rename the lock to make that obvious. We'll also add a lock around the c_ovq in the next commit, so there's no ambiguity. Signed-off-by: Amit Shah Reviewed-by: Asias He Reviewed-by: Wanlong Gao Signed-off-by: Rusty Russell Cc: stable@kernel.org --- drivers/char/virtio_console.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e6ba6b7887e9..2dd9134faa27 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -149,7 +149,7 @@ struct ports_device { spinlock_t ports_lock; /* To protect the vq operations for the control channel */ - spinlock_t cvq_lock; + spinlock_t c_ivq_lock; /* The current config space is stored here */ struct virtio_console_config config; @@ -1709,23 +1709,23 @@ static void control_work_handler(struct work_struct *work) portdev = container_of(work, struct ports_device, control_work); vq = portdev->c_ivq; - spin_lock(&portdev->cvq_lock); + spin_lock(&portdev->c_ivq_lock); while ((buf = virtqueue_get_buf(vq, &len))) { - spin_unlock(&portdev->cvq_lock); + spin_unlock(&portdev->c_ivq_lock); buf->len = len; buf->offset = 0; handle_control_message(portdev, buf); - spin_lock(&portdev->cvq_lock); + spin_lock(&portdev->c_ivq_lock); if (add_inbuf(portdev->c_ivq, buf) < 0) { dev_warn(&portdev->vdev->dev, "Error adding buffer to queue\n"); free_buf(buf, false); } } - spin_unlock(&portdev->cvq_lock); + spin_unlock(&portdev->c_ivq_lock); } static void out_intr(struct virtqueue *vq) @@ -1996,10 +1996,11 @@ static int virtcons_probe(struct virtio_device *vdev) if (multiport) { unsigned int nr_added_bufs; - spin_lock_init(&portdev->cvq_lock); + spin_lock_init(&portdev->c_ivq_lock); INIT_WORK(&portdev->control_work, &control_work_handler); - nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); + nr_added_bufs = fill_queue(portdev->c_ivq, + &portdev->c_ivq_lock); if (!nr_added_bufs) { dev_err(&vdev->dev, "Error allocating buffers for control queue\n"); @@ -2150,7 +2151,7 @@ static int virtcons_restore(struct virtio_device *vdev) return ret; if (use_multiport(portdev)) - fill_queue(portdev->c_ivq, &portdev->cvq_lock); + fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); list_for_each_entry(port, &portdev->ports, list) { port->in_vq = portdev->in_vqs[port->id]; -- cgit v1.2.3 From 9ba5c80b1aea8648a3efe5f22dc1f7cacdfbeeb8 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Fri, 29 Mar 2013 16:30:08 +0530 Subject: virtio: console: add locking around c_ovq operations When multiple ovq operations are being performed (lots of open/close operations on virtio_console fds), the __send_control_msg() function can get confused without locking. A simple recipe to cause badness is: * create a QEMU VM with two virtio-serial ports * in the guest, do while true;do echo abc >/dev/vport0p1;done while true;do echo edf >/dev/vport0p2;done In one run, this caused a panic in __send_control_msg(). In another, I got virtio_console virtio0: control-o:id 0 is not a head! This also results repeated messages similar to these on the host: qemu-kvm: virtio-serial-bus: Unexpected port id 478762112 for device virtio-serial-bus.0 qemu-kvm: virtio-serial-bus: Unexpected port id 478762368 for device virtio-serial-bus.0 Reported-by: FuXiangChun Signed-off-by: Amit Shah Reviewed-by: Wanlong Gao Reviewed-by: Asias He Signed-off-by: Rusty Russell Cc: stable@kernel.org --- drivers/char/virtio_console.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 2dd9134faa27..ce5f3fc25d6d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -150,6 +150,7 @@ struct ports_device { /* To protect the vq operations for the control channel */ spinlock_t c_ivq_lock; + spinlock_t c_ovq_lock; /* The current config space is stored here */ struct virtio_console_config config; @@ -569,11 +570,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, vq = portdev->c_ovq; sg_init_one(sg, &cpkt, sizeof(cpkt)); + + spin_lock(&portdev->c_ovq_lock); if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) { virtqueue_kick(vq); while (!virtqueue_get_buf(vq, &len)) cpu_relax(); } + spin_unlock(&portdev->c_ovq_lock); return 0; } @@ -1997,6 +2001,7 @@ static int virtcons_probe(struct virtio_device *vdev) unsigned int nr_added_bufs; spin_lock_init(&portdev->c_ivq_lock); + spin_lock_init(&portdev->c_ovq_lock); INIT_WORK(&portdev->control_work, &control_work_handler); nr_added_bufs = fill_queue(portdev->c_ivq, -- cgit v1.2.3 From a3d9052c6296ad3398d3ad649c3c682c3e7ecfa6 Mon Sep 17 00:00:00 2001 From: Mac Lin Date: Mon, 25 Mar 2013 17:23:33 +0800 Subject: ARM: cns3xxx: fix mapping of private memory region Since commit 0536bdf33faf (ARM: move iotable mappings within the vmalloc region), the Cavium CNS3xxx cannot boot anymore. This is caused by the pre-defined iotable mappings is not in the vmalloc region. This patch move the iotable mappings into the vmalloc region, and merge the MPCore private memory region (containing the SCU, the GIC and the TWD) as a single region. Signed-off-by: Mac Lin Signed-off-by: Anton Vorontsov Cc: stable@vger.kernel.org [v3.3+] --- arch/arm/mach-cns3xxx/core.c | 16 +++------------- arch/arm/mach-cns3xxx/include/mach/cns3xxx.h | 16 ++++++++-------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index e698f26cc0cb..52e4bb5cf12d 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -22,19 +22,9 @@ static struct map_desc cns3xxx_io_desc[] __initdata = { { - .virtual = CNS3XXX_TC11MP_TWD_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_TC11MP_TWD_BASE), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_CPU_BASE), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT, - .pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_DIST_BASE), - .length = SZ_4K, + .virtual = CNS3XXX_TC11MP_SCU_BASE_VIRT, + .pfn = __phys_to_pfn(CNS3XXX_TC11MP_SCU_BASE), + .length = SZ_8K, .type = MT_DEVICE, }, { .virtual = CNS3XXX_TIMER1_2_3_BASE_VIRT, diff --git a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h index 191c8e57f289..b1021aafa481 100644 --- a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h +++ b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h @@ -94,10 +94,10 @@ #define RTC_INTR_STS_OFFSET 0x34 #define CNS3XXX_MISC_BASE 0x76000000 /* Misc Control */ -#define CNS3XXX_MISC_BASE_VIRT 0xFFF07000 /* Misc Control */ +#define CNS3XXX_MISC_BASE_VIRT 0xFB000000 /* Misc Control */ #define CNS3XXX_PM_BASE 0x77000000 /* Power Management Control */ -#define CNS3XXX_PM_BASE_VIRT 0xFFF08000 +#define CNS3XXX_PM_BASE_VIRT 0xFB001000 #define PM_CLK_GATE_OFFSET 0x00 #define PM_SOFT_RST_OFFSET 0x04 @@ -109,7 +109,7 @@ #define PM_PLL_HM_PD_OFFSET 0x1C #define CNS3XXX_UART0_BASE 0x78000000 /* UART 0 */ -#define CNS3XXX_UART0_BASE_VIRT 0xFFF09000 +#define CNS3XXX_UART0_BASE_VIRT 0xFB002000 #define CNS3XXX_UART1_BASE 0x78400000 /* UART 1 */ #define CNS3XXX_UART1_BASE_VIRT 0xFFF0A000 @@ -130,7 +130,7 @@ #define CNS3XXX_I2S_BASE_VIRT 0xFFF10000 #define CNS3XXX_TIMER1_2_3_BASE 0x7C800000 /* Timer */ -#define CNS3XXX_TIMER1_2_3_BASE_VIRT 0xFFF10800 +#define CNS3XXX_TIMER1_2_3_BASE_VIRT 0xFB003000 #define TIMER1_COUNTER_OFFSET 0x00 #define TIMER1_AUTO_RELOAD_OFFSET 0x04 @@ -227,16 +227,16 @@ * Testchip peripheral and fpga gic regions */ #define CNS3XXX_TC11MP_SCU_BASE 0x90000000 /* IRQ, Test chip */ -#define CNS3XXX_TC11MP_SCU_BASE_VIRT 0xFF000000 +#define CNS3XXX_TC11MP_SCU_BASE_VIRT 0xFB004000 #define CNS3XXX_TC11MP_GIC_CPU_BASE 0x90000100 /* Test chip interrupt controller CPU interface */ -#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT 0xFF000100 +#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x100) #define CNS3XXX_TC11MP_TWD_BASE 0x90000600 -#define CNS3XXX_TC11MP_TWD_BASE_VIRT 0xFF000600 +#define CNS3XXX_TC11MP_TWD_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x600) #define CNS3XXX_TC11MP_GIC_DIST_BASE 0x90001000 /* Test chip interrupt controller distributor */ -#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT 0xFF001000 +#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x1000) #define CNS3XXX_TC11MP_L220_BASE 0x92002000 /* L220 registers */ #define CNS3XXX_TC11MP_L220_BASE_VIRT 0xFF002000 -- cgit v1.2.3 From 85762e71f17b59a76e6333d1a796737d080b7517 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 29 Mar 2013 15:40:10 -0600 Subject: ASoC: dapm: Implement mixer control sharing This is the equivalent of commit af46800 "ASoC: Implement mux control sharing", but applied to mixers instead of muxes. This allows a single control to affect multiple mixer widgets at once, which is useful when there is a single set of register bits that affects multiple mixers in HW, for example both the L and R mixers of a stereo path. Without this, you either: 1) End up with multiple controls that affect the same register bits, but whose DAPM state falls out of sync with HW, since the DAPM state is only updated for the specific control that is modified, and not for other paths that are affected by the register bit(s). 2) False paths through DAPM, since you end up merging unconnected stereo paths together into a single widget which hosts the single control, and then branching back out again, thus conjoining the enable states of the two input paths. Now that the kcontrol creation logic is split out into a separate function, dapm_create_or_share_mixmux_kcontrol(), also use that to replace most of the body of dapm_new_mux(). This should produce no functional change, but simply eliminates some mostly duplicated code. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 270 ++++++++++++++++++++++++++------------------------- 1 file changed, 136 insertions(+), 134 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1d6a9b3ceb27..687784463db9 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, return 0; } -/* create new dapm mixer control */ -static int dapm_new_mixer(struct snd_soc_dapm_widget *w) +/* + * Determine if a kcontrol is shared. If it is, look it up. If it isn't, + * create it. Either way, add the widget into the control's widget list + */ +static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, + int kci, struct snd_soc_dapm_path *path) { struct snd_soc_dapm_context *dapm = w->dapm; - int i, ret = 0; - size_t name_len, prefix_len; - struct snd_soc_dapm_path *path; struct snd_card *card = dapm->card->snd_card; const char *prefix; + size_t prefix_len; + int shared; + struct snd_kcontrol *kcontrol; struct snd_soc_dapm_widget_list *wlist; + int wlistentries; size_t wlistsize; + bool wname_in_long_name, kcname_in_long_name; + size_t name_len; + char *long_name; + const char *name; + int ret; if (dapm->codec) prefix = dapm->codec->name_prefix; @@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) else prefix_len = 0; - /* add kcontrol */ - for (i = 0; i < w->num_kcontrols; i++) { + shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], + &kcontrol); - /* match name */ - list_for_each_entry(path, &w->sources, list_sink) { + if (kcontrol) { + wlist = kcontrol->private_data; + wlistentries = wlist->num_widgets + 1; + } else { + wlist = NULL; + wlistentries = 1; + } - /* mixer/mux paths name must match control name */ - if (path->name != (char *)w->kcontrol_news[i].name) - continue; + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + wlistentries * sizeof(struct snd_soc_dapm_widget *); + wlist = krealloc(wlist, wlistsize, GFP_KERNEL); + if (wlist == NULL) { + dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n", + w->name); + return -ENOMEM; + } + wlist->num_widgets = wlistentries; + wlist->widgets[wlistentries - 1] = w; - if (w->kcontrols[i]) { - path->kcontrol = w->kcontrols[i]; - continue; + if (!kcontrol) { + if (shared) { + wname_in_long_name = false; + kcname_in_long_name = true; + } else { + switch (w->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + wname_in_long_name = true; + kcname_in_long_name = true; + break; + case snd_soc_dapm_mixer_named_ctl: + wname_in_long_name = false; + kcname_in_long_name = true; + break; + case snd_soc_dapm_mux: + case snd_soc_dapm_virt_mux: + case snd_soc_dapm_value_mux: + wname_in_long_name = true; + kcname_in_long_name = false; + break; + default: + kfree(wlist); + return -EINVAL; } + } + + if (wname_in_long_name && kcname_in_long_name) { + name_len = strlen(w->name) - prefix_len + 1 + + strlen(w->kcontrol_news[kci].name) + 1; - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - sizeof(struct snd_soc_dapm_widget *), - wlist = kzalloc(wlistsize, GFP_KERNEL); - if (wlist == NULL) { - dev_err(dapm->dev, - "ASoC: can't allocate widget list for %s\n", - w->name); + long_name = kmalloc(name_len, GFP_KERNEL); + if (long_name == NULL) { + kfree(wlist); return -ENOMEM; } - wlist->num_widgets = 1; - wlist->widgets[0] = w; - - /* add dapm control with long name. - * for dapm_mixer this is the concatenation of the - * mixer and kcontrol name. - * for dapm_mixer_named_ctl this is simply the - * kcontrol name. + + /* + * The control will get a prefix from the control + * creation process but we're also using the same + * prefix for widgets so cut the prefix off the + * front of the widget name. */ - name_len = strlen(w->kcontrol_news[i].name) + 1; - if (w->id != snd_soc_dapm_mixer_named_ctl) - name_len += 1 + strlen(w->name); + snprintf(long_name, name_len, "%s %s", + w->name + prefix_len, + w->kcontrol_news[kci].name); + long_name[name_len - 1] = '\0'; + + name = long_name; + } else if (wname_in_long_name) { + long_name = NULL; + name = w->name + prefix_len; + } else { + long_name = NULL; + name = w->kcontrol_news[kci].name; + } - path->long_name = kmalloc(name_len, GFP_KERNEL); + kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, + prefix); + ret = snd_ctl_add(card, kcontrol); + if (ret < 0) { + dev_err(dapm->dev, + "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", + w->name, name, ret); + kfree(wlist); + kfree(long_name); + return ret; + } - if (path->long_name == NULL) { - kfree(wlist); - return -ENOMEM; - } + path->long_name = long_name; + } - switch (w->id) { - default: - /* The control will get a prefix from - * the control creation process but - * we're also using the same prefix - * for widgets so cut the prefix off - * the front of the widget name. - */ - snprintf((char *)path->long_name, name_len, - "%s %s", w->name + prefix_len, - w->kcontrol_news[i].name); - break; - case snd_soc_dapm_mixer_named_ctl: - snprintf((char *)path->long_name, name_len, - "%s", w->kcontrol_news[i].name); - break; - } + kcontrol->private_data = wlist; + w->kcontrols[kci] = kcontrol; + path->kcontrol = kcontrol; - ((char *)path->long_name)[name_len - 1] = '\0'; + return 0; +} - path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], - wlist, path->long_name, - prefix); - ret = snd_ctl_add(card, path->kcontrol); - if (ret < 0) { - dev_err(dapm->dev, "ASoC: failed to add widget" - " %s dapm kcontrol %s: %d\n", - w->name, path->long_name, ret); - kfree(wlist); - kfree(path->long_name); - path->long_name = NULL; - return ret; +/* create new dapm mixer control */ +static int dapm_new_mixer(struct snd_soc_dapm_widget *w) +{ + int i, ret; + struct snd_soc_dapm_path *path; + + /* add kcontrol */ + for (i = 0; i < w->num_kcontrols; i++) { + /* match name */ + list_for_each_entry(path, &w->sources, list_sink) { + /* mixer/mux paths name must match control name */ + if (path->name != (char *)w->kcontrol_news[i].name) + continue; + + if (w->kcontrols[i]) { + path->kcontrol = w->kcontrols[i]; + continue; } - w->kcontrols[i] = path->kcontrol; + + ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); + if (ret < 0) + return ret; } } - return ret; + + return 0; } /* create new dapm mux control */ static int dapm_new_mux(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_dapm_path *path = NULL; - struct snd_kcontrol *kcontrol; - struct snd_card *card = dapm->card->snd_card; - const char *prefix; - size_t prefix_len; + struct snd_soc_dapm_path *path; int ret; - struct snd_soc_dapm_widget_list *wlist; - int shared, wlistentries; - size_t wlistsize; - const char *name; if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return -EINVAL; } - shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0], - &kcontrol); - if (kcontrol) { - wlist = kcontrol->private_data; - wlistentries = wlist->num_widgets + 1; - } else { - wlist = NULL; - wlistentries = 1; - } - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - wlistentries * sizeof(struct snd_soc_dapm_widget *), - wlist = krealloc(wlist, wlistsize, GFP_KERNEL); - if (wlist == NULL) { - dev_err(dapm->dev, - "ASoC: can't allocate widget list for %s\n", w->name); - return -ENOMEM; - } - wlist->num_widgets = wlistentries; - wlist->widgets[wlistentries - 1] = w; - - if (!kcontrol) { - if (dapm->codec) - prefix = dapm->codec->name_prefix; - else - prefix = NULL; - - if (shared) { - name = w->kcontrol_news[0].name; - prefix_len = 0; - } else { - name = w->name; - if (prefix) - prefix_len = strlen(prefix) + 1; - else - prefix_len = 0; - } - - /* - * The control will get a prefix from the control creation - * process but we're also using the same prefix for widgets so - * cut the prefix off the front of the widget name. - */ - kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, - name + prefix_len, prefix); - ret = snd_ctl_add(card, kcontrol); - if (ret < 0) { - dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n", - w->name, ret); - kfree(wlist); - return ret; - } + path = list_first_entry(&w->sources, struct snd_soc_dapm_path, + list_sink); + if (!path) { + dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name); + return -EINVAL; } - kcontrol->private_data = wlist; - - w->kcontrols[0] = kcontrol; + ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path); + if (ret < 0) + return ret; list_for_each_entry(path, &w->sources, list_sink) - path->kcontrol = kcontrol; + path->kcontrol = w->kcontrols[0]; return 0; } -- cgit v1.2.3 From dbf520a9d7d4d5ba28d2947be11e34099a5e3e20 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sun, 31 Mar 2013 00:04:40 +0000 Subject: Revert "lockdep: check that no locks held at freeze time" This reverts commit 6aa9707099c4b25700940eb3d016f16c4434360d. Commit 6aa9707099c4 ("lockdep: check that no locks held at freeze time") causes problems with NFS root filesystems. The failures were noticed on OMAP2 and 3 boards during kernel init: [ BUG: swapper/0/1 still has locks held! ] 3.9.0-rc3-00344-ga937536 #1 Not tainted ------------------------------------- 1 lock held by swapper/0/1: #0: (&type->s_umount_key#13/1){+.+.+.}, at: [] sget+0x248/0x574 stack backtrace: rpc_wait_bit_killable __wait_on_bit out_of_line_wait_on_bit __rpc_execute rpc_run_task rpc_call_sync nfs_proc_get_root nfs_get_root nfs_fs_mount_common nfs_try_mount nfs_fs_mount mount_fs vfs_kern_mount do_mount sys_mount do_mount_root mount_root prepare_namespace kernel_init_freeable kernel_init Although the rootfs mounts, the system is unstable. Here's a transcript from a PM test: http://www.pwsan.com/omap/testlogs/test_v3.9-rc3/20130317194234/pm/37xxevm/37xxevm_log.txt Here's what the test log should look like: http://www.pwsan.com/omap/testlogs/test_v3.8/20130218214403/pm/37xxevm/37xxevm_log.txt Mailing list discussion is here: http://lkml.org/lkml/2013/3/4/221 Deal with this for v3.9 by reverting the problem commit, until folks can figure out the right long-term course of action. Signed-off-by: Paul Walmsley Cc: Mandeep Singh Baines Cc: Jeff Layton Cc: Shawn Guo Cc: Cc: Fengguang Wu Cc: Trond Myklebust Cc: Ingo Molnar Cc: Ben Chan Cc: Oleg Nesterov Cc: Tejun Heo Cc: Rafael J. Wysocki Cc: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/debug_locks.h | 4 ++-- include/linux/freezer.h | 3 --- kernel/exit.c | 2 +- kernel/lockdep.c | 17 +++++++++-------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index a975de1ff59f..3bd46f766751 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -51,7 +51,7 @@ struct task_struct; extern void debug_show_all_locks(void); extern void debug_show_held_locks(struct task_struct *task); extern void debug_check_no_locks_freed(const void *from, unsigned long len); -extern void debug_check_no_locks_held(void); +extern void debug_check_no_locks_held(struct task_struct *task); #else static inline void debug_show_all_locks(void) { @@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len) } static inline void -debug_check_no_locks_held(void) +debug_check_no_locks_held(struct task_struct *task) { } #endif diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 043a5cf8b5ba..e70df40d84f6 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -3,7 +3,6 @@ #ifndef FREEZER_H_INCLUDED #define FREEZER_H_INCLUDED -#include #include #include #include @@ -49,8 +48,6 @@ extern void thaw_kernel_threads(void); static inline bool try_to_freeze(void) { - if (!(current->flags & PF_NOFREEZE)) - debug_check_no_locks_held(); might_sleep(); if (likely(!freezing(current))) return false; diff --git a/kernel/exit.c b/kernel/exit.c index 51e485ca9935..60bc027c61c3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -835,7 +835,7 @@ void do_exit(long code) /* * Make sure we are holding no locks: */ - debug_check_no_locks_held(); + debug_check_no_locks_held(tsk); /* * We can do this unlocked here. The futex code uses this flag * just to verify whether the pi state cleanup has been done diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 259db207b5d9..8a0efac4f99d 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -4088,7 +4088,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) } EXPORT_SYMBOL_GPL(debug_check_no_locks_freed); -static void print_held_locks_bug(void) +static void print_held_locks_bug(struct task_struct *curr) { if (!debug_locks_off()) return; @@ -4097,21 +4097,22 @@ static void print_held_locks_bug(void) printk("\n"); printk("=====================================\n"); - printk("[ BUG: %s/%d still has locks held! ]\n", - current->comm, task_pid_nr(current)); + printk("[ BUG: lock held at task exit time! ]\n"); print_kernel_ident(); printk("-------------------------------------\n"); - lockdep_print_held_locks(current); + printk("%s/%d is exiting with locks still held!\n", + curr->comm, task_pid_nr(curr)); + lockdep_print_held_locks(curr); + printk("\nstack backtrace:\n"); dump_stack(); } -void debug_check_no_locks_held(void) +void debug_check_no_locks_held(struct task_struct *task) { - if (unlikely(current->lockdep_depth > 0)) - print_held_locks_bug(); + if (unlikely(task->lockdep_depth > 0)) + print_held_locks_bug(task); } -EXPORT_SYMBOL_GPL(debug_check_no_locks_held); void debug_show_all_locks(void) { -- cgit v1.2.3 From 07961ac7c0ee8b546658717034fe692fd12eefa9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 31 Mar 2013 15:12:43 -0700 Subject: Linux 3.9-rc5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 54d2b2a0fef0..58a165b02af1 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 9 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Unicycling Gorilla # *DOCUMENTATION* -- cgit v1.2.3 From 9593b0b1179c526436f14849a9587fd2aae12040 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 28 Mar 2013 10:39:28 +0100 Subject: NFC: microread: Fix build failure due to a new MEI bus API uuid device_id field is removed and mei_device is renamed mei_cl_device. Signed-off-by: Samuel Ortiz --- drivers/nfc/microread/mei.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index eef38cfd812e..ca33ae193935 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -32,9 +32,6 @@ #define MICROREAD_DRIVER_NAME "microread" -#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \ - 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) - struct mei_nfc_hdr { u8 cmd; u8 status; @@ -48,7 +45,7 @@ struct mei_nfc_hdr { #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) struct microread_mei_phy { - struct mei_device *mei_device; + struct mei_cl_device *device; struct nfc_hci_dev *hdev; int powered; @@ -105,14 +102,14 @@ static int microread_mei_write(void *phy_id, struct sk_buff *skb) MEI_DUMP_SKB_OUT("mei frame sent", skb); - r = mei_send(phy->device, skb->data, skb->len); + r = mei_cl_send(phy->device, skb->data, skb->len); if (r > 0) r = 0; return r; } -static void microread_event_cb(struct mei_device *device, u32 events, +static void microread_event_cb(struct mei_cl_device *device, u32 events, void *context) { struct microread_mei_phy *phy = context; @@ -120,7 +117,7 @@ static void microread_event_cb(struct mei_device *device, u32 events, if (phy->hard_fault != 0) return; - if (events & BIT(MEI_EVENT_RX)) { + if (events & BIT(MEI_CL_EVENT_RX)) { struct sk_buff *skb; int reply_size; @@ -128,7 +125,7 @@ static void microread_event_cb(struct mei_device *device, u32 events, if (!skb) return; - reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ); + reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ); if (reply_size < MEI_NFC_HEADER_SIZE) { kfree(skb); return; @@ -149,8 +146,8 @@ static struct nfc_phy_ops mei_phy_ops = { .disable = microread_mei_disable, }; -static int microread_mei_probe(struct mei_device *device, - const struct mei_id *id) +static int microread_mei_probe(struct mei_cl_device *device, + const struct mei_cl_device_id *id) { struct microread_mei_phy *phy; int r; @@ -164,9 +161,9 @@ static int microread_mei_probe(struct mei_device *device, } phy->device = device; - mei_set_clientdata(device, phy); + mei_cl_set_drvdata(device, phy); - r = mei_register_event_cb(device, microread_event_cb, phy); + r = mei_cl_register_event_cb(device, microread_event_cb, phy); if (r) { pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); goto err_out; @@ -186,9 +183,9 @@ err_out: return r; } -static int microread_mei_remove(struct mei_device *device) +static int microread_mei_remove(struct mei_cl_device *device) { - struct microread_mei_phy *phy = mei_get_clientdata(device); + struct microread_mei_phy *phy = mei_cl_get_drvdata(device); pr_info("Removing microread\n"); @@ -202,16 +199,15 @@ static int microread_mei_remove(struct mei_device *device) return 0; } -static struct mei_id microread_mei_tbl[] = { - { MICROREAD_DRIVER_NAME, MICROREAD_UUID }, +static struct mei_cl_device_id microread_mei_tbl[] = { + { MICROREAD_DRIVER_NAME }, /* required last entry */ { } }; - MODULE_DEVICE_TABLE(mei, microread_mei_tbl); -static struct mei_driver microread_driver = { +static struct mei_cl_driver microread_driver = { .id_table = microread_mei_tbl, .name = MICROREAD_DRIVER_NAME, @@ -225,7 +221,7 @@ static int microread_mei_init(void) pr_debug(DRIVER_DESC ": %s\n", __func__); - r = mei_driver_register(µread_driver); + r = mei_cl_driver_register(µread_driver); if (r) { pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n"); return r; @@ -236,7 +232,7 @@ static int microread_mei_init(void) static void microread_mei_exit(void) { - mei_driver_unregister(µread_driver); + mei_cl_driver_unregister(µread_driver); } module_init(microread_mei_init); -- cgit v1.2.3 From 1e1b812bbe1069fc8e2e372dca7d5f541c7a8ceb Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 31 Mar 2013 09:50:07 +0000 Subject: sh_eth: fix handling of no LINK signal The code handling the absent LINK signal (or the absent PSR register -- which reflects the state of this signal) is quite naive and has probably never really worked. It's probably enough to say that this code is executed only on the LINK change interrupt (sic!) but even if we actually have the signal and choose to ignore it (it might be connected to PHY's link/activity LED output as on the Renesas BOCK-W board), sh_eth_adjust_link() on which this code relies to update 'mdp->link' gets executed later than the LINK change interrupt where it is checked, and so RX/TX never get enabled via ECMR register. So, ignore the LINK changed interrupt iff LINK signal is absent (or just chosen not to be used) or PSR register is absent, and enable/disable RX/TX directly in sh_eth_adjust_link() in this case. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index bf5e3cf97c4d..1ca8b2b10adc 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1216,10 +1216,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (felic_stat & ECSR_LCHNG) { /* Link Changed */ if (mdp->cd->no_psr || mdp->no_ether_link) { - if (mdp->link == PHY_DOWN) - link_stat = 0; - else - link_stat = PHY_ST_LINK; + goto ignore_link; } else { link_stat = (sh_eth_read(ndev, PSR)); if (mdp->ether_link_active_low) @@ -1242,6 +1239,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) } } +ignore_link: if (intr_status & EESR_TWB) { /* Write buck end. unused write back interrupt */ if (intr_status & EESR_TABT) /* Transmit Abort int */ @@ -1392,12 +1390,16 @@ static void sh_eth_adjust_link(struct net_device *ndev) (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR); new_state = 1; mdp->link = phydev->link; + if (mdp->cd->no_psr || mdp->no_ether_link) + sh_eth_rcv_snd_enable(ndev); } } else if (mdp->link) { new_state = 1; mdp->link = PHY_DOWN; mdp->speed = 0; mdp->duplex = -1; + if (mdp->cd->no_psr || mdp->no_ether_link) + sh_eth_rcv_snd_disable(ndev); } if (new_state && netif_msg_link(mdp)) -- cgit v1.2.3 From 3893b27345ac0ff13c1b9ec20ad50966b810997e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 31 Mar 2013 09:54:20 +0000 Subject: sh_eth: workaround for spurious ECI interrupt At least on Renesas R8A7778, EESR.ECI interrupt seems to fire regardless of its mask in EESIPR register. I can 100% reproduce it with the following scenario: target is booted with 'ip=on' option, and so IP-Config opens SoC Ether device but doesn't get a proper reply and then succeeds with on-board SMC chip; then I login and try to bring up the SoC Ether device with 'ifconfig', and I get an ECI interrupt once request_irq() is called by sh_eth_open() (while interrupt mask in EESIPR register is all 0), if that interrupt is accompanied by a pending EESR.FRC (frame receive completion) interrupt, I get kernel oops in sh_eth_rx() because sh_eth_ring_init() hasn't been called yet! The solution I worked out is the following: in sh_eth_interrupt(), mask the interrupt status from EESR register with the interrupt mask from EESIPR register in order not to handle the disabled interrupts -- but forcing EESIPR.M_ECI bit in this mask set because we always need to fully handle EESR.ECI interrupt in sh_eth_error() in order to quench it (as it doesn't get cleared by just writing 1 to the this bit as all the other interrupts). While at it, remove unneeded initializer for 'intr_status' variable and give it *unsigned long* type, matching the type of sh_eth_read()'s result; fix comment. Signed-off-by: Sergei Shtylyov Reviewed-by: Max Filippov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 1ca8b2b10adc..44f7904e5054 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1324,12 +1324,18 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) struct sh_eth_private *mdp = netdev_priv(ndev); struct sh_eth_cpu_data *cd = mdp->cd; irqreturn_t ret = IRQ_NONE; - u32 intr_status = 0; + unsigned long intr_status; spin_lock(&mdp->lock); - /* Get interrpt stat */ + /* Get interrupt status */ intr_status = sh_eth_read(ndev, EESR); + /* Mask it with the interrupt mask, forcing ECI interrupt to be always + * enabled since it's the one that comes thru regardless of the mask, + * and we need to fully handle it in sh_eth_error() in order to quench + * it as it doesn't get cleared by just writing 1 to the ECI bit... + */ + intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI; /* Clear interrupt */ if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF | EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF | -- cgit v1.2.3 From 3340d2aae3433ad9147f6bf0adc452b324e31591 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 31 Mar 2013 10:11:04 +0000 Subject: sh_eth: make 'link' field of 'struct sh_eth_private' *int* The 'link' field of 'struct sh_eth_private' has type 'enum phy_state' while the 'link' field of 'struct phy_device' is merely *int* (having values 0 and 1) and the former field gets assigned from the latter. Make the field match, getting rid of incorrectly used PHY_DOWN value in assignments/comparisons. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 8 ++++---- drivers/net/ethernet/renesas/sh_eth.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 44f7904e5054..6ed333fe5c04 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1377,7 +1377,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) struct phy_device *phydev = mdp->phydev; int new_state = 0; - if (phydev->link != PHY_DOWN) { + if (phydev->link) { if (phydev->duplex != mdp->duplex) { new_state = 1; mdp->duplex = phydev->duplex; @@ -1391,7 +1391,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) if (mdp->cd->set_rate) mdp->cd->set_rate(ndev); } - if (mdp->link == PHY_DOWN) { + if (!mdp->link) { sh_eth_write(ndev, (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR); new_state = 1; @@ -1401,7 +1401,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) } } else if (mdp->link) { new_state = 1; - mdp->link = PHY_DOWN; + mdp->link = 0; mdp->speed = 0; mdp->duplex = -1; if (mdp->cd->no_psr || mdp->no_ether_link) @@ -1422,7 +1422,7 @@ static int sh_eth_phy_init(struct net_device *ndev) snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, mdp->mii_bus->id , mdp->phy_id); - mdp->link = PHY_DOWN; + mdp->link = 0; mdp->speed = 0; mdp->duplex = -1; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index e6655678458e..828be4515008 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -723,7 +723,7 @@ struct sh_eth_private { u32 phy_id; /* PHY ID */ struct mii_bus *mii_bus; /* MDIO bus control */ struct phy_device *phydev; /* PHY device control */ - enum phy_state link; + int link; phy_interface_t phy_interface; int msg_enable; int speed; -- cgit v1.2.3 From 6741f40d198c6a5feb23653a1efd4ca47f93d83d Mon Sep 17 00:00:00 2001 From: Joseph CHANG Date: Thu, 28 Mar 2013 23:13:42 +0000 Subject: DM9000B: driver initialization upgrade Fix bug for DM9000 revision B which contain a DSP PHY DM9000B use DSP PHY instead previouse DM9000 revisions' analog PHY, So need extra change in initialization, For explicity PHY Reset and PHY init parameter, and first DM9000_NCR reset need NCR_MAC_LBK bit by dm9000_probe(). Following DM9000_NCR reset cause by dm9000_open() clear the NCR_MAC_LBK bit. Without this fix, Power-up FIFO pointers error happen around 2% rate among Davicom's customers' boards. With this fix, All above cases can be solved. Signed-off-by: Joseph CHANG Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 214 +++++++++++++++++----------------- drivers/net/ethernet/davicom/dm9000.h | 11 +- 2 files changed, 120 insertions(+), 105 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 8cdf02503d13..9eada8e86078 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -257,6 +257,107 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count) tmp = readl(reg); } +/* + * Sleep, either by using msleep() or if we are suspending, then + * use mdelay() to sleep. + */ +static void dm9000_msleep(board_info_t *db, unsigned int ms) +{ + if (db->in_suspend) + mdelay(ms); + else + msleep(ms); +} + +/* Read a word from phyxcer */ +static int +dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) +{ + board_info_t *db = netdev_priv(dev); + unsigned long flags; + unsigned int reg_save; + int ret; + + mutex_lock(&db->addr_lock); + + spin_lock_irqsave(&db->lock, flags); + + /* Save previous register address */ + reg_save = readb(db->io_addr); + + /* Fill the phyxcer register into REG_0C */ + iow(db, DM9000_EPAR, DM9000_PHY | reg); + + /* Issue phyxcer read command */ + iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); + + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_msleep(db, 1); /* Wait read complete */ + + spin_lock_irqsave(&db->lock, flags); + reg_save = readb(db->io_addr); + + iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ + + /* The read data keeps on REG_0D & REG_0E */ + ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); + + /* restore the previous address */ + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock, flags); + + mutex_unlock(&db->addr_lock); + + dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); + return ret; +} + +/* Write a word to phyxcer */ +static void +dm9000_phy_write(struct net_device *dev, + int phyaddr_unused, int reg, int value) +{ + board_info_t *db = netdev_priv(dev); + unsigned long flags; + unsigned long reg_save; + + dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); + mutex_lock(&db->addr_lock); + + spin_lock_irqsave(&db->lock, flags); + + /* Save previous register address */ + reg_save = readb(db->io_addr); + + /* Fill the phyxcer register into REG_0C */ + iow(db, DM9000_EPAR, DM9000_PHY | reg); + + /* Fill the written data into REG_0D & REG_0E */ + iow(db, DM9000_EPDRL, value); + iow(db, DM9000_EPDRH, value >> 8); + + /* Issue phyxcer write command */ + iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); + + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_msleep(db, 1); /* Wait write complete */ + + spin_lock_irqsave(&db->lock, flags); + reg_save = readb(db->io_addr); + + iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ + + /* restore the previous address */ + writeb(reg_save, db->io_addr); + + spin_unlock_irqrestore(&db->lock, flags); + mutex_unlock(&db->addr_lock); +} + /* dm9000_set_io * * select the specified set of io routines to use with the @@ -795,6 +896,9 @@ dm9000_init_dm9000(struct net_device *dev) iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ + dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ + dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */ + ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; /* if wol is needed, then always set NCR_WAKEEN otherwise we end @@ -1201,109 +1305,6 @@ dm9000_open(struct net_device *dev) return 0; } -/* - * Sleep, either by using msleep() or if we are suspending, then - * use mdelay() to sleep. - */ -static void dm9000_msleep(board_info_t *db, unsigned int ms) -{ - if (db->in_suspend) - mdelay(ms); - else - msleep(ms); -} - -/* - * Read a word from phyxcer - */ -static int -dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) -{ - board_info_t *db = netdev_priv(dev); - unsigned long flags; - unsigned int reg_save; - int ret; - - mutex_lock(&db->addr_lock); - - spin_lock_irqsave(&db->lock,flags); - - /* Save previous register address */ - reg_save = readb(db->io_addr); - - /* Fill the phyxcer register into REG_0C */ - iow(db, DM9000_EPAR, DM9000_PHY | reg); - - iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); /* Issue phyxcer read command */ - - writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock,flags); - - dm9000_msleep(db, 1); /* Wait read complete */ - - spin_lock_irqsave(&db->lock,flags); - reg_save = readb(db->io_addr); - - iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ - - /* The read data keeps on REG_0D & REG_0E */ - ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); - - /* restore the previous address */ - writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock,flags); - - mutex_unlock(&db->addr_lock); - - dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret); - return ret; -} - -/* - * Write a word to phyxcer - */ -static void -dm9000_phy_write(struct net_device *dev, - int phyaddr_unused, int reg, int value) -{ - board_info_t *db = netdev_priv(dev); - unsigned long flags; - unsigned long reg_save; - - dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - mutex_lock(&db->addr_lock); - - spin_lock_irqsave(&db->lock,flags); - - /* Save previous register address */ - reg_save = readb(db->io_addr); - - /* Fill the phyxcer register into REG_0C */ - iow(db, DM9000_EPAR, DM9000_PHY | reg); - - /* Fill the written data into REG_0D & REG_0E */ - iow(db, DM9000_EPDRL, value); - iow(db, DM9000_EPDRH, value >> 8); - - iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); /* Issue phyxcer write command */ - - writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock, flags); - - dm9000_msleep(db, 1); /* Wait write complete */ - - spin_lock_irqsave(&db->lock,flags); - reg_save = readb(db->io_addr); - - iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - - /* restore the previous address */ - writeb(reg_save, db->io_addr); - - spin_unlock_irqrestore(&db->lock, flags); - mutex_unlock(&db->addr_lock); -} - static void dm9000_shutdown(struct net_device *dev) { @@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev) db->flags |= DM9000_PLATF_SIMPLE_PHY; #endif - dm9000_reset(db); + /* Fixing bug on dm9000_probe, takeover dm9000_reset(db), + * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo + * while probe stage. + */ + + iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST); /* try multiple times, DM9000 sometimes gets the read wrong */ for (i = 0; i < 8; i++) { diff --git a/drivers/net/ethernet/davicom/dm9000.h b/drivers/net/ethernet/davicom/dm9000.h index 55688bd1a3ef..9ce058adabab 100644 --- a/drivers/net/ethernet/davicom/dm9000.h +++ b/drivers/net/ethernet/davicom/dm9000.h @@ -69,7 +69,9 @@ #define NCR_WAKEEN (1<<6) #define NCR_FCOL (1<<4) #define NCR_FDX (1<<3) -#define NCR_LBK (3<<1) + +#define NCR_RESERVED (3<<1) +#define NCR_MAC_LBK (1<<1) #define NCR_RST (1<<0) #define NSR_SPEED (1<<7) @@ -167,5 +169,12 @@ #define ISR_LNKCHNG (1<<5) #define ISR_UNDERRUN (1<<4) +/* Davicom MII registers. + */ + +#define MII_DM_DSPCR 0x1b /* DSP Control Register */ + +#define DSPCR_INIT_PARAM 0xE100 /* DSP init parameter */ + #endif /* _DM9000X_H_ */ -- cgit v1.2.3 From 375981f2e14868be16cafbffd34a4f16a6ee01c6 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Wed, 13 Mar 2013 12:13:30 +0530 Subject: spi/s3c64xx: modified error interrupt handling and init The status of the interrupt is available in the status register, so reading the clear pending register and writing back the same value will not actually clear the pending interrupts. This patch modifies the interrupt handler to read the status register and clear the corresponding pending bit in the clear pending register. Modified the hwInit function to clear all the pending interrupts. Signed-off-by: Girish K S Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-s3c64xx.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index e862ab8853aa..4188b2faac5c 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -994,25 +994,30 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data) { struct s3c64xx_spi_driver_data *sdd = data; struct spi_master *spi = sdd->master; - unsigned int val; + unsigned int val, clr = 0; - val = readl(sdd->regs + S3C64XX_SPI_PENDING_CLR); + val = readl(sdd->regs + S3C64XX_SPI_STATUS); - val &= S3C64XX_SPI_PND_RX_OVERRUN_CLR | - S3C64XX_SPI_PND_RX_UNDERRUN_CLR | - S3C64XX_SPI_PND_TX_OVERRUN_CLR | - S3C64XX_SPI_PND_TX_UNDERRUN_CLR; - - writel(val, sdd->regs + S3C64XX_SPI_PENDING_CLR); - - if (val & S3C64XX_SPI_PND_RX_OVERRUN_CLR) + if (val & S3C64XX_SPI_ST_RX_OVERRUN_ERR) { + clr = S3C64XX_SPI_PND_RX_OVERRUN_CLR; dev_err(&spi->dev, "RX overrun\n"); - if (val & S3C64XX_SPI_PND_RX_UNDERRUN_CLR) + } + if (val & S3C64XX_SPI_ST_RX_UNDERRUN_ERR) { + clr |= S3C64XX_SPI_PND_RX_UNDERRUN_CLR; dev_err(&spi->dev, "RX underrun\n"); - if (val & S3C64XX_SPI_PND_TX_OVERRUN_CLR) + } + if (val & S3C64XX_SPI_ST_TX_OVERRUN_ERR) { + clr |= S3C64XX_SPI_PND_TX_OVERRUN_CLR; dev_err(&spi->dev, "TX overrun\n"); - if (val & S3C64XX_SPI_PND_TX_UNDERRUN_CLR) + } + if (val & S3C64XX_SPI_ST_TX_UNDERRUN_ERR) { + clr |= S3C64XX_SPI_PND_TX_UNDERRUN_CLR; dev_err(&spi->dev, "TX underrun\n"); + } + + /* Clear the pending irq by setting and then clearing it */ + writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR); + writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR); return IRQ_HANDLED; } @@ -1036,9 +1041,13 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) writel(0, regs + S3C64XX_SPI_MODE_CFG); writel(0, regs + S3C64XX_SPI_PACKET_CNT); - /* Clear any irq pending bits */ - writel(readl(regs + S3C64XX_SPI_PENDING_CLR), - regs + S3C64XX_SPI_PENDING_CLR); + /* Clear any irq pending bits, should set and clear the bits */ + val = S3C64XX_SPI_PND_RX_OVERRUN_CLR | + S3C64XX_SPI_PND_RX_UNDERRUN_CLR | + S3C64XX_SPI_PND_TX_OVERRUN_CLR | + S3C64XX_SPI_PND_TX_UNDERRUN_CLR; + writel(val, regs + S3C64XX_SPI_PENDING_CLR); + writel(0, regs + S3C64XX_SPI_PENDING_CLR); writel(0, regs + S3C64XX_SPI_SWAP_CFG); -- cgit v1.2.3 From b0b36b861e434ee1c1a64cb39259e262f79af62e Mon Sep 17 00:00:00 2001 From: Bryan Freed Date: Wed, 13 Mar 2013 11:17:40 -0700 Subject: spi: Unlock a spinlock before calling into the controller driver. spi_pump_messages() calls into a controller driver with unprepare_transfer_hardware() which is documented as "This may sleep". As in the prepare_transfer_hardware() call below, we should release the queue_lock spinlock before making the call. Rework the logic a bit to hold queue_lock to protect the 'busy' flag, then release it to call unprepare_transfer_hardware(). Signed-off-by: Bryan Freed Reviewed-by: Doug Anderson Signed-off-by: Doug Anderson Acked-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/spi/spi.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f996c600eb8c..5b96250b0628 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -543,17 +543,16 @@ static void spi_pump_messages(struct kthread_work *work) /* Lock queue and check for queue work */ spin_lock_irqsave(&master->queue_lock, flags); if (list_empty(&master->queue) || !master->running) { - if (master->busy && master->unprepare_transfer_hardware) { - ret = master->unprepare_transfer_hardware(master); - if (ret) { - spin_unlock_irqrestore(&master->queue_lock, flags); - dev_err(&master->dev, - "failed to unprepare transfer hardware\n"); - return; - } + if (!master->busy) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return; } master->busy = false; spin_unlock_irqrestore(&master->queue_lock, flags); + if (master->unprepare_transfer_hardware && + master->unprepare_transfer_hardware(master)) + dev_err(&master->dev, + "failed to unprepare transfer hardware\n"); return; } -- cgit v1.2.3 From 1ad849aee5f53353ed88d9cd3d68a51b03a7d44f Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Wed, 13 Mar 2013 14:57:43 +0100 Subject: spi/mpc512x-psc: optionally keep PSC SS asserted across xfer segmensts Some SPI slave devices require asserted chip select signal across multiple transfer segments of an SPI message. Currently the driver always de-asserts the internal SS signal for every single transfer segment of the message and ignores the 'cs_change' flag of the transfer description. Disable the internal chip select (SS) only if this is needed and indicated by the 'cs_change' flag. Without this change, each partial transfer of a surrounding multi-part SPI transaction might erroneously change the SS signal, which might prevent slaves from answering the request that was sent in a previous transfer segment because the transaction could be considered aborted (SS was de-asserted before reading the response). Reported-by: Gerhard Sittig Signed-off-by: Anatolij Gustschin Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-mpc512x-psc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 89480b281d74..3e490ee7f275 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -164,7 +164,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi, for (i = count; i > 0; i--) { data = tx_buf ? *tx_buf++ : 0; - if (len == EOFBYTE) + if (len == EOFBYTE && t->cs_change) setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF); out_8(&fifo->txdata_8, data); len--; -- cgit v1.2.3 From 2cfda637e29ce9e3df31b59f64516b2e571cc985 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 1 Apr 2013 11:48:59 -0600 Subject: EISA/PCI: Fix bus res reference Matthew found that 3.8.3 is having problems with an old (ancient) PCI-to-EISA bridge, the Intel 82375. It worked with the 3.2 kernel. He identified the 82375, but doesn't assign the struct resource *res pointer inside the struct eisa_root_device, and panics. pci_eisa_init() was using bus->resource[] directly instead of pci_bus_resource_n(). The bus->resource[] array is a PCI-internal implementation detail, and after commit 45ca9e97 (PCI: add helpers for building PCI bus resource lists) and commit 0efd5aab (PCI: add struct pci_host_bridge_window with CPU/bus address offset), bus->resource[] is not used for PCI root buses any more. The 82375 is a subtractive-decode PCI device, so handle it the same way we handle PCI-PCI bridges in subtractive-decode mode in pci_read_bridge_bases(). [bhelgaas: changelog] Reported-by: Matthew Whitehead Tested-by: Matthew Whitehead Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v3.3+ --- drivers/eisa/pci_eisa.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index cdae207028a7..ef5c3ec87432 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -22,7 +22,8 @@ static struct eisa_root_device pci_eisa_root; static int __init pci_eisa_init(struct pci_dev *pdev, const struct pci_device_id *ent) { - int rc; + int rc, i; + struct resource *res, *bus_res = NULL; if ((rc = pci_enable_device (pdev))) { printk (KERN_ERR "pci_eisa : Could not enable device %s\n", @@ -30,9 +31,30 @@ static int __init pci_eisa_init(struct pci_dev *pdev, return rc; } + /* + * The Intel 82375 PCI-EISA bridge is a subtractive-decode PCI + * device, so the resources available on EISA are the same as those + * available on the 82375 bus. This works the same as a PCI-PCI + * bridge in subtractive-decode mode (see pci_read_bridge_bases()). + * We assume other PCI-EISA bridges are similar. + * + * eisa_root_register() can only deal with a single io port resource, + * so we use the first valid io port resource. + */ + pci_bus_for_each_resource(pdev->bus, res, i) + if (res && (res->flags & IORESOURCE_IO)) { + bus_res = res; + break; + } + + if (!bus_res) { + dev_err(&pdev->dev, "No resources available\n"); + return -1; + } + pci_eisa_root.dev = &pdev->dev; - pci_eisa_root.res = pdev->bus->resource[0]; - pci_eisa_root.bus_base_addr = pdev->bus->resource[0]->start; + pci_eisa_root.res = bus_res; + pci_eisa_root.bus_base_addr = bus_res->start; pci_eisa_root.slots = EISA_MAX_SLOTS; pci_eisa_root.dma_mask = pdev->dma_mask; dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root); -- cgit v1.2.3 From c5fb301ae83bec6892e54984e6ec765c47df8e10 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 27 Mar 2013 21:28:05 -0700 Subject: EISA/PCI: Init EISA early, before PNP Matthew reported kernels fail the pci_eisa probe and are later successful with the virtual_eisa_root_init force probe without slot0. The reason for that is: PNP probing is before pci_eisa_init gets called as pci_eisa_init is called via pci_driver. pnp 00:0f has 0xc80 - 0xc84 reserved. [ 9.700409] pnp 00:0f: [io 0x0c80-0x0c84] so eisa_probe will fail from pci_eisa_init ==>eisa_root_register ==>eisa_probe path. as force_probe is not set in pci_eisa_root, it will bail early when slot0 is not probed and initialized. Try to use subsys_initcall_sync instead, and will keep following sequence: pci_subsys_init pci_eisa_init_early pnpacpi_init/isapnp_init After this patch EISA can be initialized properly, and PNP overlapping resource will not be reserved. [ 10.104434] system 00:0f: [io 0x0c80-0x0c84] could not be reserved Reported-by: Matthew Whitehead Tested-by: Matthew Whitehead Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/eisa/pci_eisa.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index ef5c3ec87432..6c3fca97d346 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -19,8 +19,7 @@ /* There is only *one* pci_eisa device per machine, right ? */ static struct eisa_root_device pci_eisa_root; -static int __init pci_eisa_init(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __init pci_eisa_init(struct pci_dev *pdev) { int rc, i; struct resource *res, *bus_res = NULL; @@ -67,22 +66,26 @@ static int __init pci_eisa_init(struct pci_dev *pdev, return 0; } -static struct pci_device_id pci_eisa_pci_tbl[] = { - { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 }, - { 0, } -}; +/* + * We have to call pci_eisa_init_early() before pnpacpi_init()/isapnp_init(). + * Otherwise pnp resource will get enabled early and could prevent eisa + * to be initialized. + * Also need to make sure pci_eisa_init_early() is called after + * x86/pci_subsys_init(). + * So need to use subsys_initcall_sync with it. + */ +static int __init pci_eisa_init_early(void) +{ + struct pci_dev *dev = NULL; + int ret; -static struct pci_driver __refdata pci_eisa_driver = { - .name = "pci_eisa", - .id_table = pci_eisa_pci_tbl, - .probe = pci_eisa_init, -}; + for_each_pci_dev(dev) + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) { + ret = pci_eisa_init(dev); + if (ret) + return ret; + } -static int __init pci_eisa_init_module (void) -{ - return pci_register_driver (&pci_eisa_driver); + return 0; } - -device_initcall(pci_eisa_init_module); -MODULE_DEVICE_TABLE(pci, pci_eisa_pci_tbl); +subsys_initcall_sync(pci_eisa_init_early); -- cgit v1.2.3 From 0f1bc12e9eddaba2baf52d020d37670dbabe3702 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 14 Mar 2013 16:27:05 +0100 Subject: clk: tegra: Allow PLLE training to succeed Under some circumstances the PLLE needs to be retrained, in which case access to the PMC registers is required. Fix this by passing a pointer to the PMC registers instead of NULL when registering the PLLE clock. Signed-off-by: Thierry Reding Acked-By: Peter De Schrijver Signed-off-by: Mike Turquette --- drivers/clk/tegra/clk-tegra20.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 1e2de7305362..f873dcefe0de 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -703,7 +703,7 @@ static void tegra20_pll_init(void) clks[pll_a_out0] = clk; /* PLLE */ - clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL, + clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, pmc_base, 0, 100000000, &pll_e_params, 0, pll_e_freq_table, NULL); clk_register_clkdev(clk, "pll_e", NULL); -- cgit v1.2.3 From 901ceba4e81e9dd6b4a3c4c37ee22000a6c5c65f Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Fri, 29 Mar 2013 19:21:21 -0700 Subject: mwifiex: limit channel number not to overflow memory Limit the channel number in scan request, or the driver scan config structure memory will be overflowed. Cc: # 3.5+ Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a44023a7bd57..8aaf56ade4d9 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1892,7 +1892,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, } } - for (i = 0; i < request->n_channels; i++) { + for (i = 0; i < min_t(u32, request->n_channels, + MWIFIEX_USER_SCAN_CHAN_MAX); i++) { chan = request->channels[i]; priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value; priv->user_scan_cfg->chan_list[i].radio_type = chan->band; -- cgit v1.2.3 From 121cdf08cc854bda4892d2c755e32ef424772ac2 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 26 Mar 2013 17:25:55 -0400 Subject: nouveau: Attempt to use platform-provided ROM image Some platforms only provide their PCI ROM via a platform-specific interface. Fall back to attempting that if all other sources fail. Signed-off-by: Matthew Garrett Signed-off-by: Bjorn Helgaas --- drivers/gpu/drm/nouveau/core/subdev/bios/base.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index e816f06637a7..0e2c1a4f1659 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -248,6 +248,22 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios) } } +static void +nouveau_bios_shadow_platform(struct nouveau_bios *bios) +{ + struct pci_dev *pdev = nv_device(bios)->pdev; + size_t size; + + void __iomem *rom = pci_platform_rom(pdev, &size); + if (rom && size) { + bios->data = kmalloc(size, GFP_KERNEL); + if (bios->data) { + memcpy_fromio(bios->data, rom, size); + bios->size = size; + } + } +} + static int nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) { @@ -288,6 +304,7 @@ nouveau_bios_shadow(struct nouveau_bios *bios) { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL }, { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL }, { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL }, + { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL }, {} }; struct methods *mthd, *best; -- cgit v1.2.3 From 06a08570085b3b20c45f45dc66dc46851ecbcb5b Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 26 Mar 2013 17:25:56 -0400 Subject: radeon: Attempt to use platform-provided ROM image Some platforms only provide their PCI ROM via a platform-specific interface. Fall back to attempting that if all other sources fail. Signed-off-by: Matthew Garrett Signed-off-by: Bjorn Helgaas --- drivers/gpu/drm/radeon/radeon_bios.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index b8015913d382..fa3c56fba294 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -99,6 +99,29 @@ static bool radeon_read_bios(struct radeon_device *rdev) return true; } +static bool radeon_read_platform_bios(struct radeon_device *rdev) +{ + uint8_t __iomem *bios; + size_t size; + + rdev->bios = NULL; + + bios = pci_platform_rom(rdev->pdev, &size); + if (!bios) { + return false; + } + + if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + return false; + } + rdev->bios = kmemdup(bios, size, GFP_KERNEL); + if (rdev->bios == NULL) { + return false; + } + + return true; +} + #ifdef CONFIG_ACPI /* ATRM is used to get the BIOS on the discrete cards in * dual-gpu systems. @@ -620,6 +643,9 @@ bool radeon_get_bios(struct radeon_device *rdev) if (r == false) { r = radeon_read_disabled_bios(rdev); } + if (r == false) { + r = radeon_read_platform_bios(rdev); + } if (r == false || rdev->bios == NULL) { DRM_ERROR("Unable to locate a BIOS ROM\n"); rdev->bios = NULL; -- cgit v1.2.3 From 0e669246dcd11ad3ecb33a6170a963c4badaa10b Mon Sep 17 00:00:00 2001 From: Ryo Tsutsui Date: Sun, 31 Mar 2013 19:19:09 +0100 Subject: ASoC: dapm: Remove redundant clear_walk() for supply widgets We already clear the walked state in dapm_widget_power_check(), no need to do it again. Signed-off-by: Ryo Tsutsui Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 687784463db9..7a61b5cc2d4f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1165,8 +1165,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) return 1; } - dapm_clear_walk(w->dapm); - return 0; } -- cgit v1.2.3 From 1059ecfa0f1eb38eba592b2f939499504013b6d5 Mon Sep 17 00:00:00 2001 From: Ryo Tsutsui Date: Mon, 1 Apr 2013 12:50:01 +0100 Subject: ASoC: dapm: Only clear paths we've walked When clearing the walked flags there is no need to clear all paths, we only need to clear the paths we actually walked. This means we can split dapm_clear_walk() into input and output versions and rather than going through all DAPM paths we can recurse down the path until we encounter paths we have not yet walked. This reduces the number of operations we need to perform and improves cache locality. [Pulled out of the vendor tree that the patch was originally generated for by me, any bugs were introduced in that process -- broonie] Signed-off-by: Ryo Tsutsui Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7a61b5cc2d4f..68acec667242 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -707,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) } /* reset 'walked' bit for each dapm path */ -static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) +static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm, + struct list_head *sink) { struct snd_soc_dapm_path *p; - list_for_each_entry(p, &dapm->card->paths, list) - p->walked = 0; + list_for_each_entry(p, sink, list_source) { + if (p->walked) { + p->walked = 0; + dapm_clear_walk_output(dapm, &p->sink->sinks); + } + } +} + +static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm, + struct list_head *source) +{ + struct snd_soc_dapm_path *p; + + list_for_each_entry(p, source, list_sink) { + if (p->walked) { + p->walked = 0; + dapm_clear_walk_input(dapm, &p->source->sources); + } + } } + /* We implement power down on suspend by checking the power state of * the ALSA card - when we are suspending the ALSA state for the card * is set to D3. @@ -983,13 +1002,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); dapm_reset(card); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { paths = is_connected_output_ep(dai->playback_widget, list); - else + dapm_clear_walk_output(&card->dapm, + &dai->playback_widget->sinks); + } else { paths = is_connected_input_ep(dai->capture_widget, list); + dapm_clear_walk_input(&card->dapm, + &dai->capture_widget->sources); + } trace_snd_soc_dapm_connected(paths, stream); - dapm_clear_walk(&card->dapm); mutex_unlock(&card->dapm_mutex); return paths; @@ -1092,9 +1115,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) DAPM_UPDATE_STAT(w, power_checks); in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); return out != 0 && in != 0; } @@ -1117,7 +1140,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) if (w->active) { in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); return in != 0; } else { return dapm_generic_check_power(w); @@ -1133,7 +1156,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) if (w->active) { out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); return out != 0; } else { return dapm_generic_check_power(w); @@ -1745,9 +1768,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, return -ENOMEM; in = is_connected_input_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_input(w->dapm, &w->sources); out = is_connected_output_ep(w, NULL); - dapm_clear_walk(w->dapm); + dapm_clear_walk_output(w->dapm, &w->sinks); ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", w->name, w->power ? "On" : "Off", -- cgit v1.2.3 From 379cf39781fdb34c75bab6ac54707bc4466f3dc4 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 12 Mar 2013 21:08:38 +0100 Subject: ASoC: codecs: remove hidden prompt The Kconfig symbol SND_SOC_OF_SIMPLE got removed in commit f0fba2ad1b6b53d5360125c41953b7afcd6deff0 ("ASoC: multi-component - ASoC Multi-Component Support"). But that commit missed one instance. Remove it now, together with the prompt it has effectively hidden ever since. Signed-off-by: Paul Bolle Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 45b72561c615..350b86458971 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -324,7 +324,7 @@ config SND_SOC_TLV320AIC23 tristate config SND_SOC_TLV320AIC26 - tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE + tristate depends on SPI config SND_SOC_TLV320AIC32X4 -- cgit v1.2.3 From c1681bf8a7b1b98edee8b862a42c19c4e53205fd Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Mon, 1 Apr 2013 09:47:56 -0700 Subject: loop: prevent bdev freeing while device in use struct block_device lifecycle is defined by its inode (see fs/block_dev.c) - block_device allocated first time we access /dev/loopXX and deallocated on bdev_destroy_inode. When we create the device "losetup /dev/loopXX afile" we want that block_device stay alive until we destroy the loop device with "losetup -d". But because we do not hold /dev/loopXX inode its counter goes 0, and inode/bdev can be destroyed at any moment. Usually it happens at memory pressure or when user drops inode cache (like in the test below). When later in loop_clr_fd() we want to use bdev we have use-after-free error with following stack: BUG: unable to handle kernel NULL pointer dereference at 0000000000000280 bd_set_size+0x10/0xa0 loop_clr_fd+0x1f8/0x420 [loop] lo_ioctl+0x200/0x7e0 [loop] lo_compat_ioctl+0x47/0xe0 [loop] compat_blkdev_ioctl+0x341/0x1290 do_filp_open+0x42/0xa0 compat_sys_ioctl+0xc1/0xf20 do_sys_open+0x16e/0x1d0 sysenter_dispatch+0x7/0x1a To prevent use-after-free we need to grab the device in loop_set_fd() and put it later in loop_clr_fd(). The issue is reprodusible on current Linus head and v3.3. Here is the test: dd if=/dev/zero of=loop.file bs=1M count=1 while [ true ]; do losetup /dev/loop0 loop.file echo 2 > /proc/sys/vm/drop_caches losetup -d /dev/loop0 done [ Doing bdgrab/bput in loop_set_fd/loop_clr_fd is safe, because every time we call loop_set_fd() we check that loop_device->lo_state is Lo_unbound and set it to Lo_bound If somebody will try to set_fd again it will get EBUSY. And if we try to loop_clr_fd() on unbound loop device we'll get ENXIO. loop_set_fd/loop_clr_fd (and any other loop ioctl) is called under loop_device->lo_ctl_mutex. ] Signed-off-by: Anatol Pomozov Cc: Al Viro Signed-off-by: Linus Torvalds --- drivers/block/loop.c | 9 ++++++++- fs/block_dev.c | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index fe5f6403417f..2c127f9c3f3b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -922,6 +922,11 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->lo_flags |= LO_FLAGS_PARTSCAN; if (lo->lo_flags & LO_FLAGS_PARTSCAN) ioctl_by_bdev(bdev, BLKRRPART, 0); + + /* Grab the block_device to prevent its destruction after we + * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev). + */ + bdgrab(bdev); return 0; out_clr: @@ -1031,8 +1036,10 @@ static int loop_clr_fd(struct loop_device *lo) memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); memset(lo->lo_file_name, 0, LO_NAME_SIZE); - if (bdev) + if (bdev) { + bdput(bdev); invalidate_bdev(bdev); + } set_capacity(lo->lo_disk, 0); loop_sysfs_exit(lo); if (bdev) { diff --git a/fs/block_dev.c b/fs/block_dev.c index aea605c98ba6..aae187a7f94a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -551,6 +551,7 @@ struct block_device *bdgrab(struct block_device *bdev) ihold(bdev->bd_inode); return bdev; } +EXPORT_SYMBOL(bdgrab); long nr_blockdev_pages(void) { -- cgit v1.2.3 From da259465d7526804b21d274281fb4d60b4216c82 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Apr 2013 01:25:09 +0200 Subject: USB / PM: Don't try to hide PM QoS flags from usb_port_device_release() Remove the call to dev_pm_qos_hide_flags(), added by commit 6e30d7cb "usb: Add driver/usb/core/(port.c,hub.h) files", from usb_port_device_release(), because (1) it is completely unnecessary (the flags have been removed already by the PM core during the unregistration of the device object) and (2) it triggers a NULL pointer dereference in sysfs_find_dirent() (dev->kobj.sd is NULL at this point). Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 797f9d514732..65d4e55552c6 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -67,7 +67,6 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); - dev_pm_qos_hide_flags(dev); kfree(port_dev); } -- cgit v1.2.3 From 0f703069296664eb7c649c837cc8bb936c3ef07f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 2 Apr 2013 01:25:24 +0200 Subject: PM / QoS: Avoid possible deadlock related to sysfs access Commit b81ea1b (PM / QoS: Fix concurrency issues and memory leaks in device PM QoS) put calls to pm_qos_sysfs_add_latency(), pm_qos_sysfs_add_flags(), pm_qos_sysfs_remove_latency(), and pm_qos_sysfs_remove_flags() under dev_pm_qos_mtx, which was a mistake, because it may lead to deadlocks in some situations. For example, if pm_qos_remote_wakeup_store() is run in parallel with dev_pm_qos_constraints_destroy(), they may deadlock in the following way: ====================================================== [ INFO: possible circular locking dependency detected ] 3.9.0-rc4-next-20130328-sasha-00014-g91a3267 #319 Tainted: G W ------------------------------------------------------- trinity-child6/12371 is trying to acquire lock: (s_active#54){++++.+}, at: [] sysfs_addrm_finish+0x31/0x60 but task is already holding lock: (dev_pm_qos_mtx){+.+.+.}, at: [] dev_pm_qos_constraints_destroy+0x23/0x250 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (dev_pm_qos_mtx){+.+.+.}: [] lock_acquire+0x1aa/0x240 [] __mutex_lock_common+0x59/0x5e0 [] mutex_lock_nested+0x3f/0x50 [] dev_pm_qos_update_flags+0x3f/0xc0 [] pm_qos_remote_wakeup_store+0x3f/0x70 [] dev_attr_store+0x13/0x20 [] sysfs_write_file+0xfa/0x150 [] __kernel_write+0x81/0x150 [] write_pipe_buf+0x4d/0x80 [] splice_from_pipe_feed+0x7c/0x120 [] __splice_from_pipe+0x45/0x80 [] splice_from_pipe+0x4c/0x70 [] default_file_splice_write+0x18/0x30 [] do_splice_from+0x83/0xb0 [] direct_splice_actor+0x1e/0x20 [] splice_direct_to_actor+0xe7/0x200 [] do_splice_direct+0x4c/0x70 [] do_sendfile+0x169/0x300 [] SyS_sendfile64+0x64/0xb0 [] tracesys+0xe1/0xe6 -> #0 (s_active#54){++++.+}: [] __lock_acquire+0x15bf/0x1e50 [] lock_acquire+0x1aa/0x240 [] sysfs_deactivate+0x122/0x1a0 [] sysfs_addrm_finish+0x31/0x60 [] sysfs_hash_and_remove+0x7f/0xb0 [] sysfs_unmerge_group+0x51/0x70 [] pm_qos_sysfs_remove_flags+0x14/0x20 [] __dev_pm_qos_hide_flags+0x30/0x70 [] dev_pm_qos_constraints_destroy+0x35/0x250 [] dpm_sysfs_remove+0x11/0x50 [] device_del+0x3f/0x1b0 [] device_unregister+0x48/0x60 [] usb_hub_remove_port_device+0x1c/0x20 [] hub_disconnect+0xdd/0x160 [] usb_unbind_interface+0x67/0x170 [] __device_release_driver+0x87/0xe0 [] device_release_driver+0x29/0x40 [] bus_remove_device+0x148/0x160 [] device_del+0x14f/0x1b0 [] usb_disable_device+0xf9/0x280 [] usb_set_configuration+0x268/0x840 [] usb_remove_store+0x4c/0x80 [] dev_attr_store+0x13/0x20 [] sysfs_write_file+0xfa/0x150 [] do_loop_readv_writev+0x4d/0x90 [] do_readv_writev+0xf9/0x1e0 [] vfs_writev+0x3a/0x60 [] SyS_writev+0x50/0xd0 [] tracesys+0xe1/0xe6 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(dev_pm_qos_mtx); lock(s_active#54); lock(dev_pm_qos_mtx); lock(s_active#54); *** DEADLOCK *** To avoid that, remove the calls to functions mentioned above from under dev_pm_qos_mtx and introduce a separate lock to prevent races between functions that add or remove device PM QoS sysfs attributes from happening. Reported-by: Sasha Levin Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 60 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 5f74587ef258..71671c42ef45 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -46,6 +46,7 @@ #include "power.h" static DEFINE_MUTEX(dev_pm_qos_mtx); +static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx); static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); @@ -216,12 +217,17 @@ void dev_pm_qos_constraints_destroy(struct device *dev) struct pm_qos_constraints *c; struct pm_qos_flags *f; - mutex_lock(&dev_pm_qos_mtx); + mutex_lock(&dev_pm_qos_sysfs_mtx); /* * If the device's PM QoS resume latency limit or PM QoS flags have been * exposed to user space, they have to be hidden at this point. */ + pm_qos_sysfs_remove_latency(dev); + pm_qos_sysfs_remove_flags(dev); + + mutex_lock(&dev_pm_qos_mtx); + __dev_pm_qos_hide_latency_limit(dev); __dev_pm_qos_hide_flags(dev); @@ -254,6 +260,8 @@ void dev_pm_qos_constraints_destroy(struct device *dev) out: mutex_unlock(&dev_pm_qos_mtx); + + mutex_unlock(&dev_pm_qos_sysfs_mtx); } /** @@ -558,6 +566,14 @@ static void __dev_pm_qos_drop_user_request(struct device *dev, kfree(req); } +static void dev_pm_qos_drop_user_request(struct device *dev, + enum dev_pm_qos_req_type type) +{ + mutex_lock(&dev_pm_qos_mtx); + __dev_pm_qos_drop_user_request(dev, type); + mutex_unlock(&dev_pm_qos_mtx); +} + /** * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space. * @dev: Device whose PM QoS latency limit is to be exposed to user space. @@ -581,6 +597,8 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) return ret; } + mutex_lock(&dev_pm_qos_sysfs_mtx); + mutex_lock(&dev_pm_qos_mtx); if (IS_ERR_OR_NULL(dev->power.qos)) @@ -591,26 +609,27 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) if (ret < 0) { __dev_pm_qos_remove_request(req); kfree(req); + mutex_unlock(&dev_pm_qos_mtx); goto out; } - dev->power.qos->latency_req = req; + + mutex_unlock(&dev_pm_qos_mtx); + ret = pm_qos_sysfs_add_latency(dev); if (ret) - __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); + dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); out: - mutex_unlock(&dev_pm_qos_mtx); + mutex_unlock(&dev_pm_qos_sysfs_mtx); return ret; } EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); static void __dev_pm_qos_hide_latency_limit(struct device *dev) { - if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) { - pm_qos_sysfs_remove_latency(dev); + if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); - } } /** @@ -619,9 +638,15 @@ static void __dev_pm_qos_hide_latency_limit(struct device *dev) */ void dev_pm_qos_hide_latency_limit(struct device *dev) { + mutex_lock(&dev_pm_qos_sysfs_mtx); + + pm_qos_sysfs_remove_latency(dev); + mutex_lock(&dev_pm_qos_mtx); __dev_pm_qos_hide_latency_limit(dev); mutex_unlock(&dev_pm_qos_mtx); + + mutex_unlock(&dev_pm_qos_sysfs_mtx); } EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); @@ -649,6 +674,8 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val) } pm_runtime_get_sync(dev); + mutex_lock(&dev_pm_qos_sysfs_mtx); + mutex_lock(&dev_pm_qos_mtx); if (IS_ERR_OR_NULL(dev->power.qos)) @@ -659,16 +686,19 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val) if (ret < 0) { __dev_pm_qos_remove_request(req); kfree(req); + mutex_unlock(&dev_pm_qos_mtx); goto out; } - dev->power.qos->flags_req = req; + + mutex_unlock(&dev_pm_qos_mtx); + ret = pm_qos_sysfs_add_flags(dev); if (ret) - __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); out: - mutex_unlock(&dev_pm_qos_mtx); + mutex_unlock(&dev_pm_qos_sysfs_mtx); pm_runtime_put(dev); return ret; } @@ -676,10 +706,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags); static void __dev_pm_qos_hide_flags(struct device *dev) { - if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) { - pm_qos_sysfs_remove_flags(dev); + if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); - } } /** @@ -689,9 +717,15 @@ static void __dev_pm_qos_hide_flags(struct device *dev) void dev_pm_qos_hide_flags(struct device *dev) { pm_runtime_get_sync(dev); + mutex_lock(&dev_pm_qos_sysfs_mtx); + + pm_qos_sysfs_remove_flags(dev); + mutex_lock(&dev_pm_qos_mtx); __dev_pm_qos_hide_flags(dev); mutex_unlock(&dev_pm_qos_mtx); + + mutex_unlock(&dev_pm_qos_sysfs_mtx); pm_runtime_put(dev); } EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags); -- cgit v1.2.3 From 5faaa035ddc16d3d2e31c0bfc1c4756b6869dbcc Mon Sep 17 00:00:00 2001 From: Rajagopal Venkat Date: Thu, 21 Mar 2013 13:28:25 +0000 Subject: PM / devfreq: Fix compiler warnings for CONFIG_PM_DEVFREQ unset Fix compiler warnings generated when devfreq is not enabled (CONFIG_PM_DEVFREQ is not set). Signed-off-by: Rajagopal Venkat Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- include/linux/devfreq.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index e83ef39b3bea..fe8c4476f7e4 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -213,7 +213,7 @@ struct devfreq_simple_ondemand_data { #endif #else /* !CONFIG_PM_DEVFREQ */ -static struct devfreq *devfreq_add_device(struct device *dev, +static inline struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, const char *governor_name, void *data) @@ -221,34 +221,34 @@ static struct devfreq *devfreq_add_device(struct device *dev, return NULL; } -static int devfreq_remove_device(struct devfreq *devfreq) +static inline int devfreq_remove_device(struct devfreq *devfreq) { return 0; } -static int devfreq_suspend_device(struct devfreq *devfreq) +static inline int devfreq_suspend_device(struct devfreq *devfreq) { return 0; } -static int devfreq_resume_device(struct devfreq *devfreq) +static inline int devfreq_resume_device(struct devfreq *devfreq) { return 0; } -static struct opp *devfreq_recommended_opp(struct device *dev, +static inline struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags) { - return -EINVAL; + return ERR_PTR(-EINVAL); } -static int devfreq_register_opp_notifier(struct device *dev, +static inline int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { return -EINVAL; } -static int devfreq_unregister_opp_notifier(struct device *dev, +static inline int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) { return -EINVAL; -- cgit v1.2.3 From f5c3ef21db149ba573a3f079df287f3d8b05ee13 Mon Sep 17 00:00:00 2001 From: Paolo Pisati Date: Thu, 28 Mar 2013 09:24:29 +0000 Subject: cpufreq: check OF node /cpus presence before dereferencing it Check for the presence of the '/cpus' OF node before dereferencing it blindly: [ 4.181793] Unable to handle kernel NULL pointer dereference at virtual address 0000001c [ 4.181793] pgd = c0004000 [ 4.181823] [0000001c] *pgd=00000000 [ 4.181823] Internal error: Oops: 5 [#1] SMP ARM [ 4.181823] Modules linked in: [ 4.181823] CPU: 1 Tainted: G W (3.8.0-15-generic #25~hbankD) [ 4.181854] PC is at of_get_next_child+0x64/0x70 [ 4.181854] LR is at of_get_next_child+0x24/0x70 [ 4.181854] pc : [] lr : [] psr: 60000113 [ 4.181854] sp : ed891ec0 ip : ed891ec0 fp : ed891ed4 [ 4.181884] r10: c04dafd0 r9 : c098690c r8 : c0936208 [ 4.181884] r7 : ed890000 r6 : c0a63d00 r5 : 00000000 r4 : 00000000 [ 4.181884] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : c0b2acc8 [ 4.181884] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 4.181884] Control: 10c5387d Table: adcb804a DAC: 00000015 [ 4.181915] Process swapper/0 (pid: 1, stack limit = 0xed890238) [ 4.181915] Stack: (0xed891ec0 to 0xed892000) [ 4.181915] 1ec0: c09b7b70 00000007 ed891efc ed891ed8 c04daff4 c04fd9c0 00000000 c09b7b70 [ 4.181915] 1ee0: 00000007 c0a63d00 ed890000 c0936208 ed891f54 ed891f00 c00088e0 c04dafdc [ 4.181945] 1f00: ed891f54 ed891f10 c006e940 00000000 00000000 00000007 00000007 c08a4914 [ 4.181945] 1f20: 00000000 c07dbd30 c0a63d00 c09b7b70 00000007 c0a63d00 000000bc c0936208 [ 4.181945] 1f40: c098690c c0986914 ed891f94 ed891f58 c0936a40 c00087bc 00000007 00000007 [ 4.181976] 1f60: c0936208 be8bda20 b6eea010 c0a63d00 c064547c 00000000 00000000 00000000 [ 4.181976] 1f80: 00000000 00000000 ed891fac ed891f98 c0645498 c09368c8 00000000 00000000 [ 4.181976] 1fa0: 00000000 ed891fb0 c0014658 c0645488 00000000 00000000 00000000 00000000 [ 4.182006] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 4.182006] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 [ 4.182037] [] (of_get_next_child+0x64/0x70) from [] (cpu0_cpufreq_driver_init+0x24/0x284) [ 4.182067] [] (cpu0_cpufreq_driver_init+0x24/0x284) from [] (do_one_initcall+0x130/0x1b0) [ 4.182067] [] (do_one_initcall+0x130/0x1b0) from [] (kernel_init_freeable+0x184/0x24c) [ 4.182098] [] (kernel_init_freeable+0x184/0x24c) from [] (kernel_init+0x1c/0xf4) [ 4.182128] [] (kernel_init+0x1c/0xf4) from [] (ret_from_fork+0x14/0x20) [ 4.182128] Code: f57ff04f e320f004 e89da830 e89da830 (e595001c) [ 4.182128] ---[ end trace 634903a22e8609cb ]--- [ 4.182189] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 4.182189] [ 4.642395] CPU0: stopping [rjw: Changelog] Signed-off-by: Paolo Pisati Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-cpu0.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 4e5b7fb8927c..37d23a0f8c56 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -178,10 +178,16 @@ static struct cpufreq_driver cpu0_cpufreq_driver = { static int cpu0_cpufreq_probe(struct platform_device *pdev) { - struct device_node *np; + struct device_node *np, *parent; int ret; - for_each_child_of_node(of_find_node_by_path("/cpus"), np) { + parent = of_find_node_by_path("/cpus"); + if (!parent) { + pr_err("failed to find OF /cpus\n"); + return -ENOENT; + } + + for_each_child_of_node(parent, np) { if (of_get_property(np, "operating-points", NULL)) break; } -- cgit v1.2.3 From 29896178cff0cd6e4ee78edc26158cc197a6b504 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Apr 2013 00:21:08 +0000 Subject: ACPI / SPI: Use parent's ACPI_HANDLE() in acpi_register_spi_devices() The ACPI handle of struct spi_master's dev member should not be set, because this causes that struct spi_master to be associated with the ACPI device node corresponding to its parent as the second "physical_device", which is incorrect (this happens during the registration of struct spi_master). Consequently, acpi_register_spi_devices() should use the ACPI handle of the parent of the struct spi_master it is called for rather than that struct spi_master's ACPI handle (which should be NULL). Make that happen and modify the spi-pxa2xx driver, which currently is the only driver for ACPI-enumerated SPI controller chips, not to set the ACPI handle for the struct spi_master it creates. Signed-off-by: Rafael J. Wysocki Acked-by: Mika Westerberg Acked-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 1 - drivers/spi/spi.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 90b27a3508a6..810413883c79 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1168,7 +1168,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->dev.parent = &pdev->dev; master->dev.of_node = pdev->dev.of_node; - ACPI_HANDLE_SET(&master->dev, ACPI_HANDLE(&pdev->dev)); /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f996c600eb8c..5e073d897edb 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -984,7 +984,7 @@ static void acpi_register_spi_devices(struct spi_master *master) acpi_status status; acpi_handle handle; - handle = ACPI_HANDLE(&master->dev); + handle = ACPI_HANDLE(master->dev.parent); if (!handle) return; -- cgit v1.2.3 From ea81531de23cf92085e0601178fae920141caa5d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 21 Mar 2013 12:50:39 +0100 Subject: s390/uaccess: fix page table walk When translating user space addresses to kernel addresses the follow_table() function had two bugs: - PROT_NONE mappings could be read accessed via the kernel mapping. That is e.g. putting a filename into a user page, then protecting the page with PROT_NONE and afterwards issuing the "open" syscall with a pointer to the filename would incorrectly succeed. - when walking the page tables it used the pgd/pud/pmd/pte primitives which with dynamic page tables give no indication which real level of page tables is being walked (region2, region3, segment or page table). So in case of an exception the translation exception code passed to __handle_fault() is not necessarily correct. This is not really an issue since __handle_fault() doesn't evaluate the code. Only in case of e.g. a SIGBUS this code gets passed to user space. If user space can do something sane with the value is a different question though. To fix these issues don't use any Linux primitives. Only walk the page tables like the hardware would do it, however we leave quite some checks away since we know that we only have full size page tables and each index is within bounds. In theory this should fix all issues... Signed-off-by: Heiko Carstens Reviewed-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/pgtable.h | 1 + arch/s390/lib/uaccess_pt.c | 81 +++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 4a2930844d43..1686d8f0f878 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -344,6 +344,7 @@ extern unsigned long MODULES_END; #define _REGION3_ENTRY_CO 0x100 /* change-recording override */ /* Bits in the segment table entry */ +#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 6771fdd89377..466fb3383960 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -77,42 +77,69 @@ static size_t copy_in_kernel(size_t count, void __user *to, * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address * contains the (negative) exception code. */ -static __always_inline unsigned long follow_table(struct mm_struct *mm, - unsigned long addr, int write) +#ifdef CONFIG_64BIT +static unsigned long follow_table(struct mm_struct *mm, + unsigned long address, int write) { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *ptep; + unsigned long *table = (unsigned long *)__pa(mm->pgd); + + switch (mm->context.asce_bits & _ASCE_TYPE_MASK) { + case _ASCE_TYPE_REGION1: + table = table + ((address >> 53) & 0x7ff); + if (unlikely(*table & _REGION_ENTRY_INV)) + return -0x39UL; + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); + case _ASCE_TYPE_REGION2: + table = table + ((address >> 42) & 0x7ff); + if (unlikely(*table & _REGION_ENTRY_INV)) + return -0x3aUL; + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); + case _ASCE_TYPE_REGION3: + table = table + ((address >> 31) & 0x7ff); + if (unlikely(*table & _REGION_ENTRY_INV)) + return -0x3bUL; + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); + case _ASCE_TYPE_SEGMENT: + table = table + ((address >> 20) & 0x7ff); + if (unlikely(*table & _SEGMENT_ENTRY_INV)) + return -0x10UL; + if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) { + if (write && (*table & _SEGMENT_ENTRY_RO)) + return -0x04UL; + return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) + + (address & ~_SEGMENT_ENTRY_ORIGIN_LARGE); + } + table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN); + } + table = table + ((address >> 12) & 0xff); + if (unlikely(*table & _PAGE_INVALID)) + return -0x11UL; + if (write && (*table & _PAGE_RO)) + return -0x04UL; + return (*table & PAGE_MASK) + (address & ~PAGE_MASK); +} - pgd = pgd_offset(mm, addr); - if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) - return -0x3aUL; +#else /* CONFIG_64BIT */ - pud = pud_offset(pgd, addr); - if (pud_none(*pud) || unlikely(pud_bad(*pud))) - return -0x3bUL; +static unsigned long follow_table(struct mm_struct *mm, + unsigned long address, int write) +{ + unsigned long *table = (unsigned long *)__pa(mm->pgd); - pmd = pmd_offset(pud, addr); - if (pmd_none(*pmd)) + table = table + ((address >> 20) & 0x7ff); + if (unlikely(*table & _SEGMENT_ENTRY_INV)) return -0x10UL; - if (pmd_large(*pmd)) { - if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO)) - return -0x04UL; - return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK); - } - if (unlikely(pmd_bad(*pmd))) - return -0x10UL; - - ptep = pte_offset_map(pmd, addr); - if (!pte_present(*ptep)) + table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN); + table = table + ((address >> 12) & 0xff); + if (unlikely(*table & _PAGE_INVALID)) return -0x11UL; - if (write && (!pte_write(*ptep) || !pte_dirty(*ptep))) + if (write && (*table & _PAGE_RO)) return -0x04UL; - - return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK); + return (*table & PAGE_MASK) + (address & ~PAGE_MASK); } +#endif /* CONFIG_64BIT */ + static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, size_t n, int write_user) { -- cgit v1.2.3 From 765a0cac566c938821ae26efb4aa53b7502ee82c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 23 Mar 2013 10:29:01 +0100 Subject: s390/mm: provide emtpy check_pgt_cache() function All architectures need to provide a check_pgt_cache() function. The s390 one got lost somewhere. So reintroduce it to prevent future compile errors e.g. if Thomas Gleixner's idle loop rework patches get merged. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/pgtable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 1686d8f0f878..4a5443118cfb 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -1532,7 +1532,8 @@ extern int s390_enable_sie(void); /* * No page table caches to initialise */ -#define pgtable_cache_init() do { } while (0) +static inline void pgtable_cache_init(void) { } +static inline void check_pgt_cache(void) { } #include -- cgit v1.2.3 From 477fc03f5baaf5906ce04beba7dbcd0e5d1e9b30 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 29 Mar 2013 03:40:00 +0200 Subject: fbmon: use VESA_DMT_VSYNC_HIGH to fix typo VESA_DMT_VSYNC_HIGH should be used instead of VESA_DMT_HSYNC_HIGH, because FB_SYNC_VERT_HIGH_ACT is related to vsync, not to hsync. Signed-off-by: Jingoo Han Acked-by: Steffen Trumtrar Signed-off-by: Tomi Valkeinen --- drivers/video/fbmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 94ad0f71383c..7f6709991a5c 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -1400,7 +1400,7 @@ int fb_videomode_from_videomode(const struct videomode *vm, fbmode->vmode = 0; if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) fbmode->sync |= FB_SYNC_HOR_HIGH_ACT; - if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) + if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH) fbmode->sync |= FB_SYNC_VERT_HIGH_ACT; if (vm->data_flags & DISPLAY_FLAGS_INTERLACED) fbmode->vmode |= FB_VMODE_INTERLACED; -- cgit v1.2.3 From 090da752cdd6f0786eee68c8dea8db7c8abd3798 Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Sat, 30 Mar 2013 04:53:00 +0200 Subject: video:uvesafb: Fix dereference NULL pointer code path platform_device_alloc could failed and return NULL, we should check this before call platform_device_put. Signed-off-by: Wang YanQing Signed-off-by: Tomi Valkeinen --- drivers/video/uvesafb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index b75db0186488..d4284458377e 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -1973,7 +1973,8 @@ static int uvesafb_init(void) err = -ENOMEM; if (err) { - platform_device_put(uvesafb_device); + if (uvesafb_device) + platform_device_put(uvesafb_device); platform_driver_unregister(&uvesafb_driver); cn_del_callback(&uvesafb_cn_id); return err; -- cgit v1.2.3 From beb0ff390e208e71668a1389e3db02631a88cff5 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 2 Apr 2013 12:26:15 +0000 Subject: cpufreq: Correct header guards typo It should be "governor". Signed-off-by: Borislav Petkov Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 46bde01eee62..cc4bd2f6838a 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -14,8 +14,8 @@ * published by the Free Software Foundation. */ -#ifndef _CPUFREQ_GOVERNER_H -#define _CPUFREQ_GOVERNER_H +#ifndef _CPUFREQ_GOVERNOR_H +#define _CPUFREQ_GOVERNOR_H #include #include @@ -175,4 +175,4 @@ bool need_load_eval(struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate); int cpufreq_governor_dbs(struct dbs_data *dbs_data, struct cpufreq_policy *policy, unsigned int event); -#endif /* _CPUFREQ_GOVERNER_H */ +#endif /* _CPUFREQ_GOVERNOR_H */ -- cgit v1.2.3 From b34bb1ee71158d5b0f9028fb98afd026202bcfe9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Apr 2013 00:25:03 +0000 Subject: ACPI / I2C: Use parent's ACPI_HANDLE() in acpi_i2c_register_devices() The ACPI handle of struct i2c_adapter's dev member should not be set, because this causes that struct i2c_adapter to be associated with the ACPI device node corresponding to its parent as the second "physical_device", which is incorrect (this happens during the registration of struct i2c_adapter). Consequently, acpi_i2c_register_devices() should use the ACPI handle of the parent of the struct i2c_adapter it is called for rather than the struct i2c_adapter's ACPI handle (which should be NULL). Make that happen and modify the i2c-designware-platdrv driver, which currently is the only driver for ACPI-enumerated I2C controller chips, not to set the ACPI handle for the struct i2c_adapter it creates. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Acked-by: Mika Westerberg Acked-by: Wolfram Sang --- drivers/acpi/acpi_i2c.c | 2 +- drivers/i2c/busses/i2c-designware-platdrv.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c index 82045e3f5cac..a82c7626aa9b 100644 --- a/drivers/acpi/acpi_i2c.c +++ b/drivers/acpi/acpi_i2c.c @@ -90,7 +90,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adapter) acpi_handle handle; acpi_status status; - handle = ACPI_HANDLE(&adapter->dev); + handle = ACPI_HANDLE(adapter->dev.parent); if (!handle) return; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0ceb6e1b0f65..e3085c487ace 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -182,7 +182,6 @@ static int dw_i2c_probe(struct platform_device *pdev) adap->algo = &i2c_dw_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - ACPI_HANDLE_SET(&adap->dev, ACPI_HANDLE(&pdev->dev)); r = i2c_add_numbered_adapter(adap); if (r) { -- cgit v1.2.3 From 6240a10dc55a954ce05a86d2f4bc27e473b6352c Mon Sep 17 00:00:00 2001 From: Alex Shi Date: Tue, 2 Apr 2013 01:56:54 +0200 Subject: cpuidle / ACPI: recover percpu ACPI processor cstate Commit ac3ebafa81af76d6 "ACPI / idle: remove usage of the statedata" changed the percpu processor cstate to a unified cstate in ACPI idle. That caused all our NHM boxes to boot hang or panic. 2178751 Task dump for CPU 1: 2178752 swapper/1 R running task 6736 0 1 0x00000000 2178753 ffff8801e8029dc8 ffffffff8101cf96 ffff8801e8029e28 ffffffff813d294b 2178754 0000000000000f99 0000000000000003 00000000003cf654 0000000025c17d03 2178755 ffff8801e8029e38 ffff8801e74fc000 00000002590dc5c4 ffffffff8163cdb0 2178756 Call Trace: 2178757 [] ? acpi_processor_ffh_cstate_enter+0x2d/0x2f 2178758 [] acpi_idle_enter_bm+0x1b1/0x236 2178759 [] ? disable_cpuidle+0x10/0x10 2178760 [] cpuidle_enter+0x12/0x14 2178761 [] cpuidle_wrap_enter+0x2f/0x6d 2178762 [] cpuidle_enter_tk+0x10/0x12 2178763 [] cpuidle_enter_state+0x12/0x3a 2178764 [] cpuidle_idle_call+0xe8/0x161 2178765 [] cpu_idle+0x5e/0xa4 2178766 [] start_secondary+0x1a9/0x1ad 2178767 Task dump for CPU 2: In fact, the ACPI idle is based on the assumption of difference percpu cstate structures that are necessary for the implementation to work cprrectly. A unique acpi_processor_cx is not sifficient by far. This patch is just a quick fix re-introducing the percpu cstates. If someone really wants to unify the ACPI cstates, please make sure that the whole software infrastructure is changed and take hardware as well as many different kinds of BIOS settings into account. [rjw: Changelog] Reported-by: LKP project Reported-by: Xie ChanglongX Tested-by: Yinghai Lu Signed-off-by: Alex Shi Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index fc95308e9a11..ee255c60bdac 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -66,7 +66,8 @@ module_param(latency_factor, uint, 0644); static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); -static struct acpi_processor_cx *acpi_cstate[CPUIDLE_STATE_MAX]; +static DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], + acpi_cstate); static int disabled_by_idle_boot_param(void) { @@ -722,7 +723,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = acpi_cstate[index]; + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); pr = __this_cpu_read(processors); @@ -745,7 +746,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, */ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) { - struct acpi_processor_cx *cx = acpi_cstate[index]; + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); ACPI_FLUSH_CPU_CACHE(); @@ -775,7 +776,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = acpi_cstate[index]; + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); pr = __this_cpu_read(processors); @@ -833,7 +834,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = acpi_cstate[index]; + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); pr = __this_cpu_read(processors); @@ -960,7 +961,7 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) continue; #endif - acpi_cstate[count] = cx; + per_cpu(acpi_cstate[count], dev->cpu) = cx; count++; if (count == CPUIDLE_STATE_MAX) -- cgit v1.2.3 From fcd99434fb5c137274d2e15dd2a6a7455f0f29ff Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 2 Apr 2013 05:15:16 +0000 Subject: bonding: get netdev_rx_handler_unregister out of locks Now that netdev_rx_handler_unregister contains synchronize_net(), we need to call it outside of bond->lock, cause it might sleep. Also, remove the already unneded synchronize_net(). Signed-off-by: Veaceslav Falico Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6bbd90e1123c..a51241b2e621 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1976,12 +1976,11 @@ static int __bond_release_one(struct net_device *bond_dev, return -EINVAL; } + write_unlock_bh(&bond->lock); /* unregister rx_handler early so bond_handle_frame wouldn't be called * for this slave anymore. */ netdev_rx_handler_unregister(slave_dev); - write_unlock_bh(&bond->lock); - synchronize_net(); write_lock_bh(&bond->lock); if (!all && !bond->params.fail_over_mac) { -- cgit v1.2.3 From bab6a9eac05360db25c81b0090f6b1195dd986cc Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Tue, 2 Apr 2013 16:49:45 +0300 Subject: net/mlx4_en: Fix setting initial MAC address Commit 6bbb6d9 "net/mlx4_en: Optimize Rx fast path filter checks" introduced a regression under which the MAC address read from the card was not converted correctly (the most significant byte was not handled), fix that. Reviewed-by: Or Gerlitz Signed-off-by: Yan Burman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index f278b10ef714..30d78f806dc3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -411,8 +411,8 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac) { - unsigned int i; - for (i = ETH_ALEN - 1; i; --i) { + int i; + for (i = ETH_ALEN - 1; i >= 0; --i) { dst_mac[i] = src_mac & 0xff; src_mac >>= 8; } -- cgit v1.2.3 From 2dc958fa2fe6987e7ab106bd97029a09a82fcd8d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 1 Apr 2013 11:40:51 +0400 Subject: ipc: set msg back to -EAGAIN if copy wasn't performed Make sure that msg pointer is set back to error value in case of MSG_COPY flag is set and desired message to copy wasn't found. This garantees that msg is either a error pointer or a copy address. Otherwise the last message in queue will be freed without unlinking from the queue (which leads to memory corruption) and the dummy allocated copy won't be released. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Linus Torvalds --- ipc/msg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ipc/msg.c b/ipc/msg.c index 31cd1bf6af27..fede1d06ef30 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -872,6 +872,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, goto out_unlock; break; } + msg = ERR_PTR(-EAGAIN); } else break; msg_counter++; -- cgit v1.2.3 From f0f6ee1f70c4eaab9d52cf7d255df4bd89f8d1c2 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Mon, 1 Apr 2013 03:01:32 +0000 Subject: cbq: incorrect processing of high limits currently cbq works incorrectly for limits > 10% real link bandwidth, and practically does not work for limits > 50% real link bandwidth. Below are results of experiments taken on 1 Gbit link In shaper | Actual Result -----------+--------------- 100M | 108 Mbps 200M | 244 Mbps 300M | 412 Mbps 500M | 893 Mbps This happen because of q->now changes incorrectly in cbq_dequeue(): when it is called before real end of packet transmitting, L2T is greater than real time delay, q_now gets an extra boost but never compensate it. To fix this problem we prevent change of q->now until its synchronization with real time. Signed-off-by: Vasily Averin Reviewed-by: Alexey Kuznetsov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 13aa47aa2ffb..1bc210ffcba2 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -962,8 +962,11 @@ cbq_dequeue(struct Qdisc *sch) cbq_update(q); if ((incr -= incr2) < 0) incr = 0; + q->now += incr; + } else { + if (now > q->now) + q->now = now; } - q->now += incr; q->now_rt = now; for (;;) { -- cgit v1.2.3 From 25fb6ca4ed9cad72f14f61629b68dc03c0d9713f Mon Sep 17 00:00:00 2001 From: Balakumaran Kannan Date: Tue, 2 Apr 2013 16:15:05 +0530 Subject: net IPv6 : Fix broken IPv6 routing table after loopback down-up IPv6 Routing table becomes broken once we do ifdown, ifup of the loopback(lo) interface. After down-up, routes of other interface's IPv6 addresses through 'lo' are lost. IPv6 addresses assigned to all interfaces are routed through 'lo' for internal communication. Once 'lo' is down, those routing entries are removed from routing table. But those removed entries are not being re-created properly when 'lo' is brought up. So IPv6 addresses of other interfaces becomes unreachable from the same machine. Also this breaks communication with other machines because of NDISC packet processing failure. This patch fixes this issue by reading all interface's IPv6 addresses and adding them to IPv6 routing table while bringing up 'lo'. ==Testing== Before applying the patch: $ route -A inet6 Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If 2000::20/128 :: U 256 0 0 eth0 fe80::/64 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo ::1/128 :: Un 0 1 0 lo 2000::20/128 :: Un 0 1 0 lo fe80::xxxx:xxxx:xxxx:xxxx/128 :: Un 0 1 0 lo ff00::/8 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo $ sudo ifdown lo $ sudo ifup lo $ route -A inet6 Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If 2000::20/128 :: U 256 0 0 eth0 fe80::/64 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo ::1/128 :: Un 0 1 0 lo ff00::/8 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo $ After applying the patch: $ route -A inet6 Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If 2000::20/128 :: U 256 0 0 eth0 fe80::/64 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo ::1/128 :: Un 0 1 0 lo 2000::20/128 :: Un 0 1 0 lo fe80::xxxx:xxxx:xxxx:xxxx/128 :: Un 0 1 0 lo ff00::/8 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo $ sudo ifdown lo $ sudo ifup lo $ route -A inet6 Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If 2000::20/128 :: U 256 0 0 eth0 fe80::/64 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo ::1/128 :: Un 0 1 0 lo 2000::20/128 :: Un 0 1 0 lo fe80::xxxx:xxxx:xxxx:xxxx/128 :: Un 0 1 0 lo ff00::/8 :: U 256 0 0 eth0 ::/0 :: !n -1 1 1 lo $ Signed-off-by: Balakumaran Kannan Signed-off-by: Maruthi Thotad Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 26512250e095..a459c4f5b769 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2529,6 +2529,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) static void init_loopback(struct net_device *dev) { struct inet6_dev *idev; + struct net_device *sp_dev; + struct inet6_ifaddr *sp_ifa; + struct rt6_info *sp_rt; /* ::1 */ @@ -2540,6 +2543,30 @@ static void init_loopback(struct net_device *dev) } add_addr(idev, &in6addr_loopback, 128, IFA_HOST); + + /* Add routes to other interface's IPv6 addresses */ + for_each_netdev(dev_net(dev), sp_dev) { + if (!strcmp(sp_dev->name, dev->name)) + continue; + + idev = __in6_dev_get(sp_dev); + if (!idev) + continue; + + read_lock_bh(&idev->lock); + list_for_each_entry(sp_ifa, &idev->addr_list, if_list) { + + if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) + continue; + + sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0); + + /* Failure cases are ignored */ + if (!IS_ERR(sp_rt)) + ip6_ins_rt(sp_rt); + } + read_unlock_bh(&idev->lock); + } } static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) -- cgit v1.2.3 From 990454b5a48babde44a23c0f22bae5523f4fdf13 Mon Sep 17 00:00:00 2001 From: Reilly Grant Date: Mon, 1 Apr 2013 11:41:52 -0700 Subject: VSOCK: Handle changes to the VMCI context ID. The VMCI context ID of a virtual machine may change at any time. There is a VMCI event which signals this but datagrams may be processed before this is handled. It is therefore necessary to be flexible about the destination context ID of any datagrams received. (It can be assumed to be correct because it is provided by the hypervisor.) The context ID on existing sockets should be updated to reflect how the hypervisor is currently referring to the system. Signed-off-by: Reilly Grant Acked-by: Andy King Signed-off-by: David S. Miller --- net/vmw_vsock/af_vsock.c | 6 +++--- net/vmw_vsock/vmci_transport.c | 31 ++++++++++++++++++++----------- net/vmw_vsock/vsock_addr.c | 10 ---------- net/vmw_vsock/vsock_addr.h | 2 -- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index ca511c4f388a..d8079daf1bde 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -207,7 +207,7 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr) struct vsock_sock *vsk; list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) - if (vsock_addr_equals_addr_any(addr, &vsk->local_addr)) + if (addr->svm_port == vsk->local_addr.svm_port) return sk_vsock(vsk); return NULL; @@ -220,8 +220,8 @@ static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src, list_for_each_entry(vsk, vsock_connected_sockets(src, dst), connected_table) { - if (vsock_addr_equals_addr(src, &vsk->remote_addr) - && vsock_addr_equals_addr(dst, &vsk->local_addr)) { + if (vsock_addr_equals_addr(src, &vsk->remote_addr) && + dst->svm_port == vsk->local_addr.svm_port) { return sk_vsock(vsk); } } diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index a70ace83a153..1f6508e249ae 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -464,19 +464,16 @@ static struct sock *vmci_transport_get_pending( struct vsock_sock *vlistener; struct vsock_sock *vpending; struct sock *pending; + struct sockaddr_vm src; + + vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); vlistener = vsock_sk(listener); list_for_each_entry(vpending, &vlistener->pending_links, pending_links) { - struct sockaddr_vm src; - struct sockaddr_vm dst; - - vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); - vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port); - if (vsock_addr_equals_addr(&src, &vpending->remote_addr) && - vsock_addr_equals_addr(&dst, &vpending->local_addr)) { + pkt->dst_port == vpending->local_addr.svm_port) { pending = sk_vsock(vpending); sock_hold(pending); goto found; @@ -739,10 +736,15 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) */ bh_lock_sock(sk); - if (!sock_owned_by_user(sk) && sk->sk_state == SS_CONNECTED) - vmci_trans(vsk)->notify_ops->handle_notify_pkt( - sk, pkt, true, &dst, &src, - &bh_process_pkt); + if (!sock_owned_by_user(sk)) { + /* The local context ID may be out of date, update it. */ + vsk->local_addr.svm_cid = dst.svm_cid; + + if (sk->sk_state == SS_CONNECTED) + vmci_trans(vsk)->notify_ops->handle_notify_pkt( + sk, pkt, true, &dst, &src, + &bh_process_pkt); + } bh_unlock_sock(sk); @@ -902,6 +904,9 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) lock_sock(sk); + /* The local context ID may be out of date. */ + vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context; + switch (sk->sk_state) { case SS_LISTEN: vmci_transport_recv_listen(sk, pkt); @@ -958,6 +963,10 @@ static int vmci_transport_recv_listen(struct sock *sk, pending = vmci_transport_get_pending(sk, pkt); if (pending) { lock_sock(pending); + + /* The local context ID may be out of date. */ + vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context; + switch (pending->sk_state) { case SS_CONNECTING: err = vmci_transport_recv_connecting_server(sk, diff --git a/net/vmw_vsock/vsock_addr.c b/net/vmw_vsock/vsock_addr.c index b7df1aea7c59..ec2611b4ea0e 100644 --- a/net/vmw_vsock/vsock_addr.c +++ b/net/vmw_vsock/vsock_addr.c @@ -64,16 +64,6 @@ bool vsock_addr_equals_addr(const struct sockaddr_vm *addr, } EXPORT_SYMBOL_GPL(vsock_addr_equals_addr); -bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr, - const struct sockaddr_vm *other) -{ - return (addr->svm_cid == VMADDR_CID_ANY || - other->svm_cid == VMADDR_CID_ANY || - addr->svm_cid == other->svm_cid) && - addr->svm_port == other->svm_port; -} -EXPORT_SYMBOL_GPL(vsock_addr_equals_addr_any); - int vsock_addr_cast(const struct sockaddr *addr, size_t len, struct sockaddr_vm **out_addr) { diff --git a/net/vmw_vsock/vsock_addr.h b/net/vmw_vsock/vsock_addr.h index cdfbcefdf843..9ccd5316eac0 100644 --- a/net/vmw_vsock/vsock_addr.h +++ b/net/vmw_vsock/vsock_addr.h @@ -24,8 +24,6 @@ bool vsock_addr_bound(const struct sockaddr_vm *addr); void vsock_addr_unbind(struct sockaddr_vm *addr); bool vsock_addr_equals_addr(const struct sockaddr_vm *addr, const struct sockaddr_vm *other); -bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr, - const struct sockaddr_vm *other); int vsock_addr_cast(const struct sockaddr *addr, size_t len, struct sockaddr_vm **out_addr); -- cgit v1.2.3 From a8ec3a662921220fc058ed6f7f3674697876d218 Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Tue, 2 Apr 2013 09:56:10 -0400 Subject: drm: correctly restore mappings if drm_open fails If first drm_open fails, the error-handling path will incorrectly restore inode's mapping to NULL. This can cause the crash later on. Fix by separately storing away mapping pointers that drm_open can touch and restore each from its own respective variable if the call fails. Fixes: https://bugzilla.novell.com/show_bug.cgi?id=807850 (thanks to Michal Hocko for investigating investigating and finding the root cause of the bug) Reference: http://lists.freedesktop.org/archives/dri-devel/2013-March/036564.html v2: Use one variable to store file and inode mapping since they are the same at the function entry. Fix spelling mistakes in commit message. v3: Add reference to the original bug report. Reported-by: Marco Munderloh Tested-by: Marco Munderloh Signed-off-by: Ilija Hadzic Cc: Michal Hocko Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 13fdcd10a605..429e07d0b0f1 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -123,6 +123,7 @@ int drm_open(struct inode *inode, struct file *filp) int retcode = 0; int need_setup = 0; struct address_space *old_mapping; + struct address_space *old_imapping; minor = idr_find(&drm_minors_idr, minor_id); if (!minor) @@ -137,6 +138,7 @@ int drm_open(struct inode *inode, struct file *filp) if (!dev->open_count++) need_setup = 1; mutex_lock(&dev->struct_mutex); + old_imapping = inode->i_mapping; old_mapping = dev->dev_mapping; if (old_mapping == NULL) dev->dev_mapping = &inode->i_data; @@ -159,8 +161,8 @@ int drm_open(struct inode *inode, struct file *filp) err_undo: mutex_lock(&dev->struct_mutex); - filp->f_mapping = old_mapping; - inode->i_mapping = old_mapping; + filp->f_mapping = old_imapping; + inode->i_mapping = old_imapping; iput(container_of(dev->dev_mapping, struct inode, i_data)); dev->dev_mapping = old_mapping; mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 8b4b9f27e57584f3d90e0bb84cf800ad81cfe3a1 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 15 Feb 2013 12:21:43 -0500 Subject: x86: remove the x32 syscall bitmask from syscall_get_nr() Commit fca460f95e928bae373daa8295877b6905bc62b8 simplified the x32 implementation by creating a syscall bitmask, equal to 0x40000000, that could be applied to x32 syscalls such that the masked syscall number would be the same as a x86_64 syscall. While that patch was a nice way to simplify the code, it went a bit too far by adding the mask to syscall_get_nr(); returning the masked syscall numbers can cause confusion with callers that expect syscall numbers matching the x32 ABI, e.g. unmasked syscall numbers. This patch fixes this by simply removing the mask from syscall_get_nr() while preserving the other changes from the original commit. While there are several syscall_get_nr() callers in the kernel, most simply check that the syscall number is greater than zero, in this case this patch will have no effect. Of those remaining callers, they appear to be few, seccomp and ftrace, and from my testing of seccomp without this patch the original commit definitely breaks things; the seccomp filter does not correctly filter the syscalls due to the difference in syscall numbers in the BPF filter and the value from syscall_get_nr(). Applying this patch restores the seccomp BPF filter functionality on x32. I've tested this patch with the seccomp BPF filters as well as ftrace and everything looks reasonable to me; needless to say general usage seemed fine as well. Signed-off-by: Paul Moore Link: http://lkml.kernel.org/r/20130215172143.12549.10292.stgit@localhost Cc: Cc: Will Drewry Cc: H. Peter Anvin Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/syscall.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index 1ace47b62592..2e188d68397c 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -29,13 +29,13 @@ extern const unsigned long sys_call_table[]; */ static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - return regs->orig_ax & __SYSCALL_MASK; + return regs->orig_ax; } static inline void syscall_rollback(struct task_struct *task, struct pt_regs *regs) { - regs->ax = regs->orig_ax & __SYSCALL_MASK; + regs->ax = regs->orig_ax; } static inline long syscall_get_error(struct task_struct *task, -- cgit v1.2.3 From b8178f130e25c1bdac1c33e0996f1ff6e20ec08e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 1 Apr 2013 15:47:39 -0600 Subject: Revert "PCI/ACPI: Request _OSC control before scanning PCI root bus" This reverts commit 8c33f51df406e1a1f7fa4e9b244845b7ebd61fa6. Conflicts: drivers/acpi/pci_root.c This commit broke some pre-1.1 PCIe devices by leaving them with ASPM enabled. Previously, we had disabled ASPM on these devices because many of them don't implement it correctly (per 149e1637). Requesting _OSC control early means that aspm_disabled may be set before we scan the PCI bus and configure link ASPM state. But the ASPM configuration currently skips the check for pre-PCIe 1.1 devices when aspm_disabled is set, like this: acpi_pci_root_add acpi_pci_osc_support if (flags != base_flags) pcie_no_aspm aspm_disabled = 1 pci_acpi_scan_root ... pcie_aspm_init_link_state pcie_aspm_sanity_check if (!aspm_disabled) /* check for pre-PCIe 1.1 device */ Therefore, setting aspm_disabled early means that we leave ASPM enabled on these pre-PCIe 1.1 devices, which is a regression for some devices. The best fix would be to clean up the ASPM init so we can evaluate _OSC before scanning the bug (that way boot-time and hot-add discovery will work the same), but that requires significant rework. For now, we'll just revert the _OSC change as the lowest-risk fix. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=55211 Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Acked-by: Yinghai Lu CC: stable@vger.kernel.org # v3.8+ --- drivers/acpi/pci_root.c | 76 ++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0ac546d5e53f..c740364d4abe 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -415,7 +415,6 @@ static int acpi_pci_root_add(struct acpi_device *device, struct acpi_pci_root *root; struct acpi_pci_driver *driver; u32 flags, base_flags; - bool is_osc_granted = false; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) @@ -476,6 +475,30 @@ static int acpi_pci_root_add(struct acpi_device *device, flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; acpi_pci_osc_support(root, flags); + /* + * TBD: Need PCI interface for enumeration/configuration of roots. + */ + + mutex_lock(&acpi_pci_root_lock); + list_add_tail(&root->node, &acpi_pci_roots); + mutex_unlock(&acpi_pci_root_lock); + + /* + * Scan the Root Bridge + * -------------------- + * Must do this prior to any attempt to bind the root device, as the + * PCI namespace does not get created until this call is made (and + * thus the root bridge's pci_dev does not exist). + */ + root->bus = pci_acpi_scan_root(root); + if (!root->bus) { + printk(KERN_ERR PREFIX + "Bus %04x:%02x not present in PCI namespace\n", + root->segment, (unsigned int)root->secondary.start); + result = -ENODEV; + goto out_del_root; + } + /* Indicate support for various _OSC capabilities. */ if (pci_ext_cfg_avail()) flags |= OSC_EXT_PCI_CONFIG_SUPPORT; @@ -494,6 +517,7 @@ static int acpi_pci_root_add(struct acpi_device *device, flags = base_flags; } } + if (!pcie_ports_disabled && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL @@ -514,54 +538,28 @@ static int acpi_pci_root_add(struct acpi_device *device, status = acpi_pci_osc_control_set(device->handle, &flags, OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); if (ACPI_SUCCESS(status)) { - is_osc_granted = true; dev_info(&device->dev, "ACPI _OSC control (0x%02x) granted\n", flags); + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { + /* + * We have ASPM control, but the FADT indicates + * that it's unsupported. Clear it. + */ + pcie_clear_aspm(root->bus); + } } else { - is_osc_granted = false; dev_info(&device->dev, "ACPI _OSC request failed (%s), " "returned control mask: 0x%02x\n", acpi_format_exception(status), flags); + pr_info("ACPI _OSC control for PCIe not granted, " + "disabling ASPM\n"); + pcie_no_aspm(); } } else { dev_info(&device->dev, - "Unable to request _OSC control " - "(_OSC support mask: 0x%02x)\n", flags); - } - - /* - * TBD: Need PCI interface for enumeration/configuration of roots. - */ - - mutex_lock(&acpi_pci_root_lock); - list_add_tail(&root->node, &acpi_pci_roots); - mutex_unlock(&acpi_pci_root_lock); - - /* - * Scan the Root Bridge - * -------------------- - * Must do this prior to any attempt to bind the root device, as the - * PCI namespace does not get created until this call is made (and - * thus the root bridge's pci_dev does not exist). - */ - root->bus = pci_acpi_scan_root(root); - if (!root->bus) { - printk(KERN_ERR PREFIX - "Bus %04x:%02x not present in PCI namespace\n", - root->segment, (unsigned int)root->secondary.start); - result = -ENODEV; - goto out_del_root; - } - - /* ASPM setting */ - if (is_osc_granted) { - if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) - pcie_clear_aspm(root->bus); - } else { - pr_info("ACPI _OSC control for PCIe not granted, " - "disabling ASPM\n"); - pcie_no_aspm(); + "Unable to request _OSC control " + "(_OSC support mask: 0x%02x)\n", flags); } pci_acpi_add_bus_pm_notifier(device, root->bus); -- cgit v1.2.3 From 6e0eda3c389887168455b92b6f7b48f552227067 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 14 Mar 2013 18:49:37 +0400 Subject: PCI: Don't try to disable Bus Master on disconnected PCI devices This is a fix for commit 7897e60227 ("PCI: Disable Bus Master unconditionally in pci_device_shutdown()"). Vivek reported that with this commit, kexec failed because none of his SATA disks came up. A ->shutdown() callback might put the device in D3cold, which means config space is no longer available. [bhelgaas: changelog] Link: https://lkml.org/lkml/2013/3/12/529 Reported-and-Tested-by: Vivek Goyal Signed-off-by: Konstantin Khlebnikov Signed-off-by: Bjorn Helgaas Cc: Rafael J. Wysocki --- drivers/pci/pci-driver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 1fa1e482a999..79277fb36c6b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -390,9 +390,10 @@ static void pci_device_shutdown(struct device *dev) /* * Turn off Bus Master bit on the device to tell it to not - * continue to do DMA + * continue to do DMA. Don't touch devices in D3cold or unknown states. */ - pci_clear_master(pci_dev); + if (pci_dev->current_state <= PCI_D3hot) + pci_clear_master(pci_dev); } #ifdef CONFIG_PM -- cgit v1.2.3 From 906b1c394d0906a154fbdc904ca506bceb515756 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 30 Mar 2013 10:23:12 +0000 Subject: netfilter: ip6t_NPT: Fix translation for non-multiple of 32 prefix lengths The bitmask used for the prefix mangling was being calculated incorrectly, leading to the wrong part of the address being replaced when the prefix length wasn't a multiple of 32. Signed-off-by: Matthias Schiffer Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/ip6t_NPT.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index 33608c610276..cb631143721c 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c @@ -57,7 +57,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, if (pfx_len - i >= 32) mask = 0; else - mask = htonl(~((1 << (pfx_len - i)) - 1)); + mask = htonl((1 << (i - pfx_len + 32)) - 1); idx = i / 32; addr->s6_addr32[idx] &= mask; -- cgit v1.2.3 From e66cd5372d09d58002b2779a3bcdc564d6348883 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 3 Apr 2013 13:17:20 +0200 Subject: ACPI / BGRT: Don't let users configure BGRT on non X86 systems Fengguang Wu's 0-Day kernel build testing backend found the following build error for an allmodconfig build on ia64: drivers/built-in.o: In function `show_yoffset': >> bgrt.c:(.text+0xe5a71): undefined reference to `bgrt_tab' >> bgrt.c:(.text+0xe5a91): undefined reference to `bgrt_tab' drivers/built-in.o: In function `show_xoffset': >> bgrt.c:(.text+0xe5b51): undefined reference to `bgrt_tab' >> bgrt.c:(.text+0xe5b71): undefined reference to `bgrt_tab' drivers/built-in.o: In function `show_type': >> bgrt.c:(.text+0xe5c31): undefined reference to `bgrt_tab' drivers/built-in.o:bgrt.c:(.text+0xe5c51): more undefined references to `bgrt_tab' follow drivers/built-in.o: In function `bgrt_init': bgrt.c:(.init.text+0x8931): undefined reference to `bgrt_image' bgrt.c:(.init.text+0x8932): undefined reference to `bgrt_image_size' bgrt.c:(.init.text+0x8950): undefined reference to `bgrt_image' bgrt.c:(.init.text+0x8960): undefined reference to `bgrt_image_size' The problem is that all these undefined names are provided by arch/x86/platform/efi/efi-bgrt.c - which is obviously not available to the ia64 build. It doesn't seem useful to provide the BGRT support for Itanium (many systems are headless and have no graphics at all). So just don't let users configure this driver on non-X86 machines. Reported-by: Fengguang Wu Acked-by: H. Peter Anvin Signed-off-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 92ed9692c47e..4bf68c8d4797 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -396,7 +396,7 @@ config ACPI_CUSTOM_METHOD config ACPI_BGRT bool "Boottime Graphics Resource Table support" - depends on EFI + depends on EFI && X86 help This driver adds support for exposing the ACPI Boottime Graphics Resource Table, which allows the operating system to obtain -- cgit v1.2.3 From 698613b63817f2f6ca79831cd1c37aae67025323 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 3 Apr 2013 16:33:26 +0100 Subject: ARM: iWMMXt: always enable iWMMXt support with PJ4 CPUs Jason Cooper reports these build errors: arch/arm/kernel/built-in.o: In function `iwmmxt_do': /.../arch/arm/kernel/pj4-cp0.c:36: undefined reference to `iwmmxt_task_release' /.../arch/arm/kernel/pj4-cp0.c:40: undefined reference to `iwmmxt_task_switch' make: *** [vmlinux] Error 1 This is caused because the PJ4 code explicitly references the iWMMXt code, but doesn't require it to be built. Fix this by ensuring that iWMMXt is always enabled with PJ4. Reported-by: Jason Cooper Signed-off-by: Russell King --- arch/arm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 13b739469c51..12ea3b3d49a9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1183,9 +1183,9 @@ config ARM_NR_BANKS default 8 config IWMMXT - bool "Enable iWMMXt support" + bool "Enable iWMMXt support" if !CPU_PJ4 depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4 - default y if PXA27x || PXA3xx || ARCH_MMP + default y if PXA27x || PXA3xx || ARCH_MMP || CPU_PJ4 help Enable support for iWMMXt context switching at run time if running on a CPU that supports it. -- cgit v1.2.3 From 6e7aceeb7c70b9ebad79bcfe91fcf738826e8e6d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 25 Mar 2013 17:02:48 +0100 Subject: ARM: 7682/1: cache-l2x0: fix masking of RTL revision numbering and set_debug init Commit b8db6b8 (ARM: 7547/4: cache-l2x0: add support for Aurora L2 cache ctrl) moved the masking of the part ID which caused the RTL version to be lost. Commit 6248d06 (ARM: 7545/1: cache-l2x0: make outer_cache_fns a field of l2x0_of_data) changed how .set_debug is initialized. Both commits break commit 74ddcdb (ARM: 7608/1: l2x0: Only set .set_debug on PL310 r3p0 and earlier) which uses the RTL version to conditionally set .set_debug function pointer. Commit b8db6b8 also caused the printed cache ID to be missing the version information. Fix this by reverting how the part number is masked so the RTL version info is maintained. The cache-id-part DT property does not set the RTL bits so masking them should have no effect. Also, re-arrange the order of the function pointer init so the .set_debug function can be overridden. Reported-by: Paolo Pisati Signed-off-by: Rob Herring Cc: Gregory CLEMENT Cc: Yehuda Yitschak Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c2f37390308a..c465faca51b0 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -299,7 +299,7 @@ static void l2x0_unlock(u32 cache_id) int lockregs; int i; - switch (cache_id) { + switch (cache_id & L2X0_CACHE_ID_PART_MASK) { case L2X0_CACHE_ID_PART_L310: lockregs = 8; break; @@ -333,15 +333,14 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) if (cache_id_part_number_from_dt) cache_id = cache_id_part_number_from_dt; else - cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID) - & L2X0_CACHE_ID_PART_MASK; + cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); aux &= aux_mask; aux |= aux_val; /* Determine the number of ways */ - switch (cache_id) { + switch (cache_id & L2X0_CACHE_ID_PART_MASK) { case L2X0_CACHE_ID_PART_L310: if (aux & (1 << 16)) ways = 16; @@ -725,7 +724,6 @@ static const struct l2x0_of_data pl310_data = { .flush_all = l2x0_flush_all, .inv_all = l2x0_inv_all, .disable = l2x0_disable, - .set_debug = pl310_set_debug, }, }; @@ -814,9 +812,8 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) data->save(); of_init = true; - l2x0_init(l2x0_base, aux_val, aux_mask); - memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache)); + l2x0_init(l2x0_base, aux_val, aux_mask); return 0; } -- cgit v1.2.3 From 93dc68876b608da041fe40ed39424b0fcd5aa2fb Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 26 Mar 2013 23:35:04 +0100 Subject: ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations) On Cortex-A15 (r0p0..r3p2) the TLBI/DSB are not adequately shooting down all use of the old entries. This patch implements the erratum workaround which consists of: 1. Dummy TLBIMVAIS and DSB on the CPU doing the TLBI operation. 2. Send IPI to the CPUs that are running the same mm (and ASID) as the one being invalidated (or all the online CPUs for global pages). 3. CPU receiving the IPI executes a DMB and CLREX (part of the exception return code already). Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/Kconfig | 10 ++++++ arch/arm/include/asm/highmem.h | 7 ++++ arch/arm/include/asm/mmu_context.h | 2 ++ arch/arm/include/asm/tlbflush.h | 15 +++++++++ arch/arm/kernel/smp_tlb.c | 66 ++++++++++++++++++++++++++++++++++++++ arch/arm/mm/context.c | 3 +- 6 files changed, 102 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 12ea3b3d49a9..1cacda426a0e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1439,6 +1439,16 @@ config ARM_ERRATA_775420 to deadlock. This workaround puts DSB before executing ISB if an abort may occur on cache maintenance. +config ARM_ERRATA_798181 + bool "ARM errata: TLBI/DSB failure on Cortex-A15" + depends on CPU_V7 && SMP + help + On Cortex-A15 (r0p0..r3p2) the TLBI*IS/DSB operations are not + adequately shooting down all use of the old entries. This + option enables the Linux kernel workaround for this erratum + which sends an IPI to the CPUs that are running the same ASID + as the one being invalidated. + endmenu source "arch/arm/common/Kconfig" diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index 8c5e828f484d..91b99abe7a95 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -41,6 +41,13 @@ extern void kunmap_high(struct page *page); #endif #endif +/* + * Needed to be able to broadcast the TLB invalidation for kmap. + */ +#ifdef CONFIG_ARM_ERRATA_798181 +#undef ARCH_NEEDS_KMAP_HIGH_GET +#endif + #ifdef ARCH_NEEDS_KMAP_HIGH_GET extern void *kmap_high_get(struct page *page); #else diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index 863a6611323c..a7b85e0d0cc1 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h @@ -27,6 +27,8 @@ void __check_vmalloc_seq(struct mm_struct *mm); void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); #define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; }) +DECLARE_PER_CPU(atomic64_t, active_asids); + #else /* !CONFIG_CPU_HAS_ASID */ #ifdef CONFIG_MMU diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 4db8c8820f0d..9e9c041358ca 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -450,6 +450,21 @@ static inline void local_flush_bp_all(void) isb(); } +#ifdef CONFIG_ARM_ERRATA_798181 +static inline void dummy_flush_tlb_a15_erratum(void) +{ + /* + * Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0. + */ + asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); + dsb(); +} +#else +static inline void dummy_flush_tlb_a15_erratum(void) +{ +} +#endif + /* * flush_pmd_entry * diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c index bd0300531399..e82e1d248772 100644 --- a/arch/arm/kernel/smp_tlb.c +++ b/arch/arm/kernel/smp_tlb.c @@ -12,6 +12,7 @@ #include #include +#include /**********************************************************************/ @@ -69,12 +70,72 @@ static inline void ipi_flush_bp_all(void *ignored) local_flush_bp_all(); } +#ifdef CONFIG_ARM_ERRATA_798181 +static int erratum_a15_798181(void) +{ + unsigned int midr = read_cpuid_id(); + + /* Cortex-A15 r0p0..r3p2 affected */ + if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2) + return 0; + return 1; +} +#else +static int erratum_a15_798181(void) +{ + return 0; +} +#endif + +static void ipi_flush_tlb_a15_erratum(void *arg) +{ + dmb(); +} + +static void broadcast_tlb_a15_erratum(void) +{ + if (!erratum_a15_798181()) + return; + + dummy_flush_tlb_a15_erratum(); + smp_call_function_many(cpu_online_mask, ipi_flush_tlb_a15_erratum, + NULL, 1); +} + +static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm) +{ + int cpu; + cpumask_t mask = { CPU_BITS_NONE }; + + if (!erratum_a15_798181()) + return; + + dummy_flush_tlb_a15_erratum(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + /* + * We only need to send an IPI if the other CPUs are running + * the same ASID as the one being invalidated. There is no + * need for locking around the active_asids check since the + * switch_mm() function has at least one dmb() (as required by + * this workaround) in case a context switch happens on + * another CPU after the condition below. + */ + if (atomic64_read(&mm->context.id) == + atomic64_read(&per_cpu(active_asids, cpu))) + cpumask_set_cpu(cpu, &mask); + } + smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1); +} + void flush_tlb_all(void) { if (tlb_ops_need_broadcast()) on_each_cpu(ipi_flush_tlb_all, NULL, 1); else local_flush_tlb_all(); + broadcast_tlb_a15_erratum(); } void flush_tlb_mm(struct mm_struct *mm) @@ -83,6 +144,7 @@ void flush_tlb_mm(struct mm_struct *mm) on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1); else local_flush_tlb_mm(mm); + broadcast_tlb_mm_a15_erratum(mm); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) @@ -95,6 +157,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) &ta, 1); } else local_flush_tlb_page(vma, uaddr); + broadcast_tlb_mm_a15_erratum(vma->vm_mm); } void flush_tlb_kernel_page(unsigned long kaddr) @@ -105,6 +168,7 @@ void flush_tlb_kernel_page(unsigned long kaddr) on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); } else local_flush_tlb_kernel_page(kaddr); + broadcast_tlb_a15_erratum(); } void flush_tlb_range(struct vm_area_struct *vma, @@ -119,6 +183,7 @@ void flush_tlb_range(struct vm_area_struct *vma, &ta, 1); } else local_flush_tlb_range(vma, start, end); + broadcast_tlb_mm_a15_erratum(vma->vm_mm); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) @@ -130,6 +195,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); } else local_flush_tlb_kernel_range(start, end); + broadcast_tlb_a15_erratum(); } void flush_bp_all(void) diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index a5a4b2bc42ba..2ac37372ef52 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -48,7 +48,7 @@ static DEFINE_RAW_SPINLOCK(cpu_asid_lock); static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION); static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS); -static DEFINE_PER_CPU(atomic64_t, active_asids); +DEFINE_PER_CPU(atomic64_t, active_asids); static DEFINE_PER_CPU(u64, reserved_asids); static cpumask_t tlb_flush_pending; @@ -215,6 +215,7 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) { local_flush_bp_all(); local_flush_tlb_all(); + dummy_flush_tlb_a15_erratum(); } atomic64_set(&per_cpu(active_asids, cpu), asid); -- cgit v1.2.3 From 6f3d90e55660ba42301b5e9c7eed332cc9f70fd7 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 28 Mar 2013 11:17:55 +0100 Subject: ARM: 7685/1: delay: use private ticks_per_jiffy field for timer-based delay ops Commit 70264367a243 ("ARM: 7653/2: do not scale loops_per_jiffy when using a constant delay clock") fixed a problem with our timer-based delay loop, where loops_per_jiffy is scaled by cpufreq yet used directly by the timer delay ops. This patch fixes the problem in a more elegant way by keeping a private ticks_per_jiffy field in the delay ops, independent of loops_per_jiffy and therefore not subject to scaling. The loop-based delay continues to use loops_per_jiffy directly, as it should. Acked-by: Nicolas Pitre Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/delay.h | 2 +- arch/arm/kernel/smp.c | 3 --- arch/arm/lib/delay.c | 8 +++++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h index 720799fd3a81..dff714d886d5 100644 --- a/arch/arm/include/asm/delay.h +++ b/arch/arm/include/asm/delay.h @@ -24,7 +24,7 @@ extern struct arm_delay_ops { void (*delay)(unsigned long); void (*const_udelay)(unsigned long); void (*udelay)(unsigned long); - bool const_clock; + unsigned long ticks_per_jiffy; } arm_delay_ops; #define __delay(n) arm_delay_ops.delay(n) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 79078edbb9bc..1f2ccccaf009 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -673,9 +673,6 @@ static int cpufreq_callback(struct notifier_block *nb, if (freq->flags & CPUFREQ_CONST_LOOPS) return NOTIFY_OK; - if (arm_delay_ops.const_clock) - return NOTIFY_OK; - if (!per_cpu(l_p_j_ref, cpu)) { per_cpu(l_p_j_ref, cpu) = per_cpu(cpu_data, cpu).loops_per_jiffy; diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c index 6b93f6a1a3c7..64dbfa57204a 100644 --- a/arch/arm/lib/delay.c +++ b/arch/arm/lib/delay.c @@ -58,7 +58,7 @@ static void __timer_delay(unsigned long cycles) static void __timer_const_udelay(unsigned long xloops) { unsigned long long loops = xloops; - loops *= loops_per_jiffy; + loops *= arm_delay_ops.ticks_per_jiffy; __timer_delay(loops >> UDELAY_SHIFT); } @@ -73,11 +73,13 @@ void __init register_current_timer_delay(const struct delay_timer *timer) pr_info("Switching to timer-based delay loop\n"); delay_timer = timer; lpj_fine = timer->freq / HZ; - loops_per_jiffy = lpj_fine; + + /* cpufreq may scale loops_per_jiffy, so keep a private copy */ + arm_delay_ops.ticks_per_jiffy = lpj_fine; arm_delay_ops.delay = __timer_delay; arm_delay_ops.const_udelay = __timer_const_udelay; arm_delay_ops.udelay = __timer_udelay; - arm_delay_ops.const_clock = true; + delay_calibrated = true; } else { pr_info("Ignoring duplicate/late registration of read_current_timer delay\n"); -- cgit v1.2.3 From b21e023ba4003fe4b5c32540e4aee5991c019e92 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 2 Apr 2013 22:11:46 +0100 Subject: ARM: 7689/1: add unwind annotations to ftrace asm Add unwind annotations to the ftrace assembly code so that the function tracer's stacktracing options (func_stack_trace, etc.) work when CONFIG_ARM_UNWIND is enabled. Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 3248cde504ed..fefd7f971437 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -276,7 +276,13 @@ ENDPROC(ftrace_graph_caller_old) */ .macro mcount_enter +/* + * This pad compensates for the push {lr} at the call site. Note that we are + * unable to unwind through a function which does not otherwise save its lr. + */ + UNWIND(.pad #4) stmdb sp!, {r0-r3, lr} + UNWIND(.save {r0-r3, lr}) .endm .macro mcount_get_lr reg @@ -289,6 +295,7 @@ ENDPROC(ftrace_graph_caller_old) .endm ENTRY(__gnu_mcount_nc) +UNWIND(.fnstart) #ifdef CONFIG_DYNAMIC_FTRACE mov ip, lr ldmia sp!, {lr} @@ -296,17 +303,22 @@ ENTRY(__gnu_mcount_nc) #else __mcount #endif +UNWIND(.fnend) ENDPROC(__gnu_mcount_nc) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller) +UNWIND(.fnstart) __ftrace_caller +UNWIND(.fnend) ENDPROC(ftrace_caller) #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(ftrace_graph_caller) +UNWIND(.fnstart) __ftrace_graph_caller +UNWIND(.fnend) ENDPROC(ftrace_graph_caller) #endif -- cgit v1.2.3 From 4e1db26a0b42e2b6e27c05d68adcc01709c2eed2 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 3 Apr 2013 12:24:45 +0100 Subject: ARM: 7690/1: mm: fix CONFIG_LPAE typos CONFIG_LPAE doesn't exist: the correct option is CONFIG_ARM_LPAE, so fix up the two typos under arch/arm/. The fix to head.S is slightly scary, but this is just for setting up an early io-mapping for the serial port when running on a big-endian, LPAE system. Since these systems don't exist in the wild (at least, I have no access to one outside of kvmtool, which doesn't provide a serial port suitable for earlyprintk), then we can revisit the code later if it causes any problems. Signed-off-by: Paul Bolle Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/head.S | 2 +- arch/arm/kernel/setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index e0eb9a1cae77..8bac553fe213 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -267,7 +267,7 @@ __create_page_tables: addne r6, r6, #1 << SECTION_SHIFT strne r6, [r3] -#if defined(CONFIG_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8) +#if defined(CONFIG_ARM_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8) sub r4, r4, #4 @ Fixup page table pointer @ for 64-bit descriptors #endif diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index f3ac13f69b7a..d343a6c3a6d1 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -544,7 +544,7 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size) size -= start & ~PAGE_MASK; bank->start = PAGE_ALIGN(start); -#ifndef CONFIG_LPAE +#ifndef CONFIG_ARM_LPAE if (bank->start + size < bank->start) { printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in " "32-bit physical address space\n", (long long)start); -- cgit v1.2.3 From 8cde7ad17e4f4ff8d12ff60dd09c0a291cb0b61c Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Wed, 3 Apr 2013 12:27:18 -0400 Subject: ext4: fix big-endian bugs which could cause fs corruptions When an extent was zeroed out, we forgot to do convert from cpu to le16. It could make us hit a BUG_ON when we try to write dirty pages out. So fix it. [ Also fix a bug found by Dmitry Monakhov where we were missing le32_to_cpu() calls in the new indirect punch hole code. There are a number of other big endian warnings found by static code analyzers, but we'll wait for the next merge window to fix them all up. These fixes are designed to be Obviously Correct by code inspection, and easy to demonstrate that it won't make any difference (and hence, won't introduce any bugs) on little endian architectures such as x86. --tytso ] Signed-off-by: Zheng Liu Signed-off-by: "Theodore Ts'o" Reported-by: CAI Qian Reported-by: Christian Kujau Cc: Dmitry Monakhov --- fs/ext4/extents.c | 11 +++++++---- fs/ext4/indirect.c | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 56efcaadf848..9c6d06dcef8b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2999,20 +2999,23 @@ static int ext4_split_extent_at(handle_t *handle, if (split_flag & EXT4_EXT_DATA_VALID1) { err = ext4_ext_zeroout(inode, ex2); zero_ex.ee_block = ex2->ee_block; - zero_ex.ee_len = ext4_ext_get_actual_len(ex2); + zero_ex.ee_len = cpu_to_le16( + ext4_ext_get_actual_len(ex2)); ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex2)); } else { err = ext4_ext_zeroout(inode, ex); zero_ex.ee_block = ex->ee_block; - zero_ex.ee_len = ext4_ext_get_actual_len(ex); + zero_ex.ee_len = cpu_to_le16( + ext4_ext_get_actual_len(ex)); ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex)); } } else { err = ext4_ext_zeroout(inode, &orig_ex); zero_ex.ee_block = orig_ex.ee_block; - zero_ex.ee_len = ext4_ext_get_actual_len(&orig_ex); + zero_ex.ee_len = cpu_to_le16( + ext4_ext_get_actual_len(&orig_ex)); ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(&orig_ex)); } @@ -3272,7 +3275,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, if (err) goto out; zero_ex.ee_block = ex->ee_block; - zero_ex.ee_len = ext4_ext_get_actual_len(ex); + zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)); ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex)); err = ext4_ext_get_access(handle, inode, path + depth); diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index b505a145a593..a04183127ef0 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -1539,9 +1539,9 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode, blk = *i_data; if (level > 0) { ext4_lblk_t first2; - bh = sb_bread(inode->i_sb, blk); + bh = sb_bread(inode->i_sb, le32_to_cpu(blk)); if (!bh) { - EXT4_ERROR_INODE_BLOCK(inode, blk, + EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk), "Read failure"); return -EIO; } -- cgit v1.2.3 From a9b977ecd3dbc5d4f0fe0b3d5c66d284859b1f2a Mon Sep 17 00:00:00 2001 From: Prathyush K Date: Tue, 2 Apr 2013 16:53:01 +0530 Subject: ASoC: Samsung: return error if drvdata is not set This patch fixes a possible crash in case drvdata for the secondary device is not set. Signed-off-by: Prathyush K Signed-off-by: Padmavathi Venna Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d7231e336a7c..f1fc06419560 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1107,6 +1107,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (samsung_dai_type == TYPE_SEC) { sec_dai = dev_get_drvdata(&pdev->dev); + if (!sec_dai) { + dev_err(&pdev->dev, "Unable to get drvdata\n"); + return -EFAULT; + } snd_soc_register_dai(&sec_dai->pdev->dev, &sec_dai->i2s_dai_drv); asoc_dma_platform_register(&pdev->dev); -- cgit v1.2.3 From c6f9b1eb0e5df468891eff17f981b76c86f95f3a Mon Sep 17 00:00:00 2001 From: Prathyush K Date: Tue, 2 Apr 2013 16:53:02 +0530 Subject: ASoC: Samsung: set drvdata before adding secondary device Currently, a new platform device is created for secondary device by calling platform_device_register_resndata and then the drvdata is set for this device. The following patch has been added to driver core: "driver core: fix possible missing of device probe". This results in the added device getting probed immediately but the drvdata for the secondary device is not yet set. This patch removes the platform_device_register_resndata call and instead calls platform_device_alloc, platform_set_drvdata and platform_device_add which fixes the above issue. Signed-off-by: Prathyush K Signed-off-by: Padmavathi Venna Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f1fc06419560..6bbeb0bf1a73 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -972,6 +972,7 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) { struct i2s_dai *i2s; + int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); if (i2s == NULL) @@ -996,15 +997,17 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.capture.channels_max = 2; i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; + dev_set_drvdata(&i2s->pdev->dev, i2s); } else { /* Create a new platform_device for Secondary */ - i2s->pdev = platform_device_register_resndata(NULL, - "samsung-i2s-sec", -1, NULL, 0, NULL, 0); + i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1); if (IS_ERR(i2s->pdev)) return NULL; - } - /* Pre-assign snd_soc_dai_set_drvdata */ - dev_set_drvdata(&i2s->pdev->dev, i2s); + platform_set_drvdata(i2s->pdev, i2s); + ret = platform_device_add(i2s->pdev); + if (ret < 0) + return NULL; + } return i2s; } -- cgit v1.2.3 From 5aa995e83ac7727b7705431e6eb2b317c59b95ba Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Apr 2013 11:00:01 +0200 Subject: ASoC: tegra: Don't claim to support PCM pause and resume The tegra dmaengine driver does not support pausing and resuming a DMA stream. The tegra PCM driver still claims to support pause and resume though and implements them by stopping and restarting the stream. This is not what an application using pause/resume would expect. Usually applications have support for working around PCMs which do not support suspend and resume, so don't set the SNDRV_PCM_INFO_PAUSE and SNDRV_PCM_INFO_RESUME flags for the tegra PCM and use the default snd_dmaengine_pcm_trigger callback. Signed-off-by: Lars-Peter Clausen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_pcm.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index c925ab0adeb6..5e2c55c5b255 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -43,8 +43,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED, .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, @@ -127,26 +125,6 @@ static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - return snd_dmaengine_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_START); - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - return snd_dmaengine_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - default: - return -EINVAL; - } - return 0; -} - static int tegra_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -164,7 +142,7 @@ static struct snd_pcm_ops tegra_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = tegra_pcm_hw_params, .hw_free = tegra_pcm_hw_free, - .trigger = tegra_pcm_trigger, + .trigger = snd_dmaengine_pcm_trigger, .pointer = snd_dmaengine_pcm_pointer, .mmap = tegra_pcm_mmap, }; -- cgit v1.2.3 From 5fa70f71dbf33603b0d29b33d8da128b266eb733 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Apr 2013 11:02:56 +0200 Subject: ASoC: dmaengine_pcm: Setup device_fc in snd_hwparams_to_dma_slave_config Usually device_fc should be set to false for audio DMAs. Initialize it in a common place so drivers don't have to do this manually. Signed-off-by: Lars-Peter Clausen Tested-by: Peter Ujfalusi Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm-dma.c | 2 -- sound/soc/fsl/imx-pcm-dma.c | 2 -- sound/soc/soc-dmaengine-pcm.c | 2 ++ 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index b8570e3e1b57..bb07989762d5 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -129,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, slave_config.src_maxburst = 1; } - slave_config.device_fc = false; - dma_chan = snd_dmaengine_pcm_get_chan(substream); if (dmaengine_slave_config(dma_chan, &slave_config)) { pr_err("atmel-pcm: failed to configure dma channel\n"); diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 6832c498457a..64af57336dbb 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -57,8 +57,6 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - slave_config.device_fc = false; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { slave_config.dst_addr = dma_params->dma_addr; slave_config.dst_maxburst = dma_params->burstsize; diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index e8b1215b8c1b..7c24dedff971 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -89,6 +89,8 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, slave_config->src_addr_width = buswidth; } + slave_config->device_fc = false; + return 0; } EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); -- cgit v1.2.3 From 85c9f9c5f9d09ea43daf4f1a8b81d3c7b7394d27 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Apr 2013 11:06:02 +0200 Subject: ASoC: dmaengine-pcm: Add a common DAI DMA data struct This patch adds a common DMA data struct which can be used by DAI drivers to communicate their DMA configuration requirements to the DMA pcm driver. Having a common data structure for this allows us to implement common functions on top of them, which can be used by multiple platforms. This patch also introduces a new function to initialize certain fields of a dma_slave_config struct from the common DAI DMA data struct. Signed-off-by: Lars-Peter Clausen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 24 ++++++++++++++++++++++++ sound/soc/soc-dmaengine-pcm.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f8a70312adb8..95620428a59b 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -44,4 +44,28 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); +/** + * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data + * @addr: Address of the DAI data source or destination register. + * @addr_width: Width of the DAI data source or destination register. + * @maxburst: Maximum number of words(note: words, as in units of the + * src_addr_width member, not bytes) that can be send to or received from the + * DAI in one burst. + * @slave_id: Slave requester id for the DMA channel. + * @filter_data: Custom DMA channel filter data, this will usually be used when + * requesting the DMA channel. + */ +struct snd_dmaengine_dai_dma_data { + dma_addr_t addr; + enum dma_slave_buswidth addr_width; + u32 maxburst; + unsigned int slave_id; + void *filter_data; +}; + +void snd_dmaengine_pcm_set_config_from_dai_data( + const struct snd_pcm_substream *substream, + const struct snd_dmaengine_dai_dma_data *dma_data, + struct dma_slave_config *config); + #endif diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 7c24dedff971..a9a300acb506 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -95,6 +95,43 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); +/** + * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config + * using DAI DMA data. + * @substream: PCM substream + * @dma_data: DAI DMA data + * @slave_config: DMA slave configuration + * + * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and + * slave_id fields of the DMA slave config from the same fields of the DAI DMA + * data struct. The src and dst fields will be initialized depending on the + * direction of the substream. If the substream is a playback stream the dst + * fields will be initialized, if it is a capture stream the src fields will be + * initialized. The {dst,src}_addr_width field will only be initialized if the + * addr_width field of the DAI DMA data struct is not equal to + * DMA_SLAVE_BUSWIDTH_UNDEFINED. + */ +void snd_dmaengine_pcm_set_config_from_dai_data( + const struct snd_pcm_substream *substream, + const struct snd_dmaengine_dai_dma_data *dma_data, + struct dma_slave_config *slave_config) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->dst_addr = dma_data->addr; + slave_config->dst_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->dst_addr_width = dma_data->addr_width; + } else { + slave_config->src_addr = dma_data->addr; + slave_config->src_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->src_addr_width = dma_data->addr_width; + } + + slave_config->slave_id = dma_data->slave_id; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data); + static void dmaengine_pcm_dma_complete(void *arg) { struct snd_pcm_substream *substream = arg; -- cgit v1.2.3 From 09ae3aaf3cd28422d76b7b78d9491b17330b276a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Apr 2013 11:06:05 +0200 Subject: ASoC: omap: Use common DAI DMA data Use the common DAI DMA data struct for omap, this allows us to use the common helper function to configure the DMA slave config based on the DAI DMA data. For omap-dmic and omap-mcpdm also move the DMA data from a global variable to the driver state struct. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/am3517evm.c | 1 - sound/soc/omap/ams-delta.c | 1 - sound/soc/omap/mcbsp.c | 14 +++++++------ sound/soc/omap/mcbsp.h | 7 ++++--- sound/soc/omap/n810.c | 1 - sound/soc/omap/omap-abe-twl6040.c | 1 - sound/soc/omap/omap-dmic.c | 22 ++++++++++---------- sound/soc/omap/omap-hdmi.c | 24 ++++++++++------------ sound/soc/omap/omap-mcbsp.c | 6 +++--- sound/soc/omap/omap-mcpdm.c | 31 +++++++++++++---------------- sound/soc/omap/omap-pcm.c | 42 +++++---------------------------------- sound/soc/omap/omap-pcm.h | 39 ------------------------------------ sound/soc/omap/omap-twl4030.c | 1 - sound/soc/omap/omap3pandora.c | 1 - sound/soc/omap/osk5912.c | 1 - sound/soc/omap/rx51.c | 1 - 16 files changed, 54 insertions(+), 139 deletions(-) delete mode 100644 sound/soc/omap/omap-pcm.h diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index c1900b2a6f28..994dcf345975 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -28,7 +28,6 @@ #include #include "omap-mcbsp.h" -#include "omap-pcm.h" #include "../codecs/tlv320aic23.h" diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 2600447fa74f..629446482a91 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -36,7 +36,6 @@ #include #include "omap-mcbsp.h" -#include "omap-pcm.h" #include "../codecs/cx20442.h" diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 285c8368cb47..eb68c7db1cf3 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev) return -ENODEV; } /* RX DMA request number, and port address configuration */ - mcbsp->dma_data[1].name = "Audio Capture"; - mcbsp->dma_data[1].dma_req = res->start; - mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1); + mcbsp->dma_req[1] = res->start; + mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1]; + mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1); + mcbsp->dma_data[1].maxburst = 4; res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); if (!res) { @@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev) return -ENODEV; } /* TX DMA request number, and port address configuration */ - mcbsp->dma_data[0].name = "Audio Playback"; - mcbsp->dma_data[0].dma_req = res->start; - mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0); + mcbsp->dma_req[0] = res->start; + mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0]; + mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0); + mcbsp->dma_data[0].maxburst = 4; mcbsp->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(mcbsp->fclk)) { diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index f93e0b0af303..96d1b086bcf8 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -24,14 +24,14 @@ #ifndef __ASOC_MCBSP_H #define __ASOC_MCBSP_H -#include "omap-pcm.h" - #ifdef CONFIG_ARCH_OMAP1 #define mcbsp_omap1() 1 #else #define mcbsp_omap1() 0 #endif +#include + /* McBSP register numbers. Register address offset = num * reg_step */ enum { /* Common registers */ @@ -312,7 +312,8 @@ struct omap_mcbsp { struct omap_mcbsp_platform_data *pdata; struct omap_mcbsp_st_data *st_data; struct omap_mcbsp_reg_cfg cfg_regs; - struct omap_pcm_dma_data dma_data[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; + unsigned int dma_req[2]; int dma_op_mode; u16 max_tx_thres; u16 max_rx_thres; diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index ee7cd53aa3ee..5e8d640d314f 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -34,7 +34,6 @@ #include #include "omap-mcbsp.h" -#include "omap-pcm.h" #define N810_HEADSET_AMP_GPIO 10 #define N810_SPEAKER_AMP_GPIO 101 diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index e7d93fa412a9..70cd5c7b2e14 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -34,7 +34,6 @@ #include "omap-dmic.h" #include "omap-mcpdm.h" -#include "omap-pcm.h" #include "../codecs/twl6040.h" struct abe_twl6040 { diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 8ebaf117d81f..a2597fab33a3 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -39,8 +39,8 @@ #include #include #include +#include -#include "omap-pcm.h" #include "omap-dmic.h" struct omap_dmic { @@ -55,13 +55,9 @@ struct omap_dmic { u32 ch_enabled; bool active; struct mutex mutex; -}; -/* - * Stream DMA parameters - */ -static struct omap_pcm_dma_data omap_dmic_dai_dma_params = { - .name = "DMIC capture", + struct snd_dmaengine_dai_dma_data dma_data; + unsigned int dma_req; }; static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) @@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream, mutex_unlock(&dmic->mutex); - snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params); + snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data); return ret; } @@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - struct omap_pcm_dma_data *dma_data; + struct snd_dmaengine_dai_dma_data *dma_data; int channels; dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); @@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream, /* packet size is threshold * channels */ dma_data = snd_soc_dai_get_dma_data(dai, substream); - dma_data->packet_size = dmic->threshold * channels; + dma_data->maxburst = dmic->threshold * channels; return 0; } @@ -476,7 +472,7 @@ static int asoc_dmic_probe(struct platform_device *pdev) ret = -ENODEV; goto err_put_clk; } - omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG; + dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG; res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!res) { @@ -484,7 +480,9 @@ static int asoc_dmic_probe(struct platform_device *pdev) ret = -ENODEV; goto err_put_clk; } - omap_dmic_dai_dma_params.dma_req = res->start; + + dmic->dma_req = res->start; + dmic->dma_data.filter_data = &dmic->dma_req; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!res) { diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index 32fa840c493e..b4bfab9f33e8 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -32,15 +32,16 @@ #include #include #include +#include #include