From e3cc067b0a79d3a3672bfe7cfba12f2e8ae56039 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 18 Sep 2009 16:31:22 -0700 Subject: xen/evtchn: track enabled state for each port enable/disable_irq() complain if the enables/disables are unbalanced, so keep track of the state and avoid redundant enables. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 71 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index af031950f9b1..4356a9a030df 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -69,10 +69,36 @@ struct per_user_data { const char *name; }; -/* Who's bound to each port? */ -static struct per_user_data *port_user[NR_EVENT_CHANNELS]; +/* + * Who's bound to each port? This is logically an array of struct + * per_user_data *, but we encode the current enabled-state in bit 0. + */ +static unsigned long port_user[NR_EVENT_CHANNELS]; static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ +static inline struct per_user_data *get_port_user(unsigned port) +{ + return (struct per_user_data *)(port_user[port] & ~1); +} + +static inline void set_port_user(unsigned port, struct per_user_data *u) +{ + port_user[port] = (unsigned long)u; +} + +static inline bool get_port_enabled(unsigned port) +{ + return port_user[port] & 1; +} + +static inline void set_port_enabled(unsigned port, bool enabled) +{ + if (enabled) + port_user[port] |= 1; + else + port_user[port] &= ~1; +} + irqreturn_t evtchn_interrupt(int irq, void *data) { unsigned int port = (unsigned long)data; @@ -80,9 +106,15 @@ irqreturn_t evtchn_interrupt(int irq, void *data) spin_lock(&port_user_lock); - u = port_user[port]; + u = get_port_user(port); + + if (WARN(!get_port_enabled(port), + "Interrupt for port %d, but apparently not enabled; per-user %p\n", + port, u)) + goto out; disable_irq_nosync(irq); + set_port_enabled(port, false); if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; @@ -92,10 +124,10 @@ irqreturn_t evtchn_interrupt(int irq, void *data) kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN); } - } else { + } else u->ring_overflow = 1; - } +out: spin_unlock(&port_user_lock); return IRQ_HANDLED; @@ -198,9 +230,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf, goto out; spin_lock_irq(&port_user_lock); - for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) - if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) - enable_irq(irq_from_evtchn(kbuf[i])); + + for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { + unsigned port = kbuf[i]; + + if (port < NR_EVENT_CHANNELS && + get_port_user(port) == u && + !get_port_enabled(port)) { + set_port_enabled(port, true); + enable_irq(irq_from_evtchn(port)); + } + } + spin_unlock_irq(&port_user_lock); rc = count; @@ -222,8 +263,8 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) * interrupt handler yet, and our caller has already * serialized bind operations.) */ - BUG_ON(port_user[port] != NULL); - port_user[port] = u; + BUG_ON(get_port_user(port) != NULL); + set_port_user(port, u); rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, u->name, (void *)(unsigned long)port); @@ -242,7 +283,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port) /* make sure we unbind the irq handler before clearing the port */ barrier(); - port_user[port] = NULL; + set_port_user(port, NULL); } static long evtchn_ioctl(struct file *file, @@ -333,7 +374,7 @@ static long evtchn_ioctl(struct file *file, spin_lock_irq(&port_user_lock); rc = -ENOTCONN; - if (port_user[unbind.port] != u) { + if (get_port_user(unbind.port) != u) { spin_unlock_irq(&port_user_lock); break; } @@ -355,7 +396,7 @@ static long evtchn_ioctl(struct file *file, if (notify.port >= NR_EVENT_CHANNELS) { rc = -EINVAL; - } else if (port_user[notify.port] != u) { + } else if (get_port_user(notify.port) != u) { rc = -ENOTCONN; } else { notify_remote_via_evtchn(notify.port); @@ -444,10 +485,10 @@ static int evtchn_release(struct inode *inode, struct file *filp) free_page((unsigned long)u->ring); for (i = 0; i < NR_EVENT_CHANNELS; i++) { - if (port_user[i] != u) + if (get_port_user(i) != u) continue; - evtchn_unbind_from_user(port_user[i], i); + evtchn_unbind_from_user(get_port_user(i), i); } spin_unlock_irq(&port_user_lock); -- cgit v1.2.3 From 93afe0b75ef3675ca05320919a57de8b9bbb159c Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 18 Sep 2009 16:36:58 -0700 Subject: xen/evtchn: dynamically allocate port_user array We only need the array when running as a Xen domain, so dynamically allocate it as needed to save on bss space. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 4356a9a030df..709c32d949bf 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -73,7 +73,7 @@ struct per_user_data { * Who's bound to each port? This is logically an array of struct * per_user_data *, but we encode the current enabled-state in bit 0. */ -static unsigned long port_user[NR_EVENT_CHANNELS]; +static unsigned long *port_user; static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ static inline struct per_user_data *get_port_user(unsigned port) @@ -522,8 +522,11 @@ static int __init evtchn_init(void) if (!xen_domain()) return -ENODEV; + port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); + if (port_user == NULL) + return -ENOMEM; + spin_lock_init(&port_user_lock); - memset(port_user, 0, sizeof(port_user)); /* Create '/dev/misc/evtchn'. */ err = misc_register(&evtchn_miscdev); @@ -539,6 +542,9 @@ static int __init evtchn_init(void) static void __exit evtchn_cleanup(void) { + kfree(port_user); + port_user = NULL; + misc_deregister(&evtchn_miscdev); } -- cgit v1.2.3 From 0edce91dcd83160019867a00746c679344dc0bbd Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 18 Sep 2009 16:55:29 -0700 Subject: xen/evtchn: ports start enabled Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 709c32d949bf..72dc7f20c5ed 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -108,10 +108,9 @@ irqreturn_t evtchn_interrupt(int irq, void *data) u = get_port_user(port); - if (WARN(!get_port_enabled(port), - "Interrupt for port %d, but apparently not enabled; per-user %p\n", - port, u)) - goto out; + WARN(!get_port_enabled(port), + "Interrupt for port %d, but apparently not enabled; per-user %p\n", + port, u); disable_irq_nosync(irq); set_port_enabled(port, false); @@ -127,7 +126,6 @@ irqreturn_t evtchn_interrupt(int irq, void *data) } else u->ring_overflow = 1; -out: spin_unlock(&port_user_lock); return IRQ_HANDLED; @@ -265,6 +263,7 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) */ BUG_ON(get_port_user(port) != NULL); set_port_user(port, u); + set_port_enabled(port, true); /* start enabled */ rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, u->name, (void *)(unsigned long)port); -- cgit v1.2.3 From 1a1a17cddbfb1f81222b3f18ee8530c41fbc3b82 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 18 Sep 2009 17:13:41 -0700 Subject: xen/evtchn: remove spurious barrier evtchn_unbind_from_user() is called under a lock, so there's no need to worry about the ordering of unbind_from_irqhandler vs clearing the port per-user data. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 72dc7f20c5ed..f79ac5ca3793 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -279,9 +279,6 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port) unbind_from_irqhandler(irq, (void *)(unsigned long)port); - /* make sure we unbind the irq handler before clearing the port */ - barrier(); - set_port_user(port, NULL); } -- cgit v1.2.3 From 3f5e554f669098c84c82ce75e7577f7e0f3fccde Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 28 May 2010 15:28:27 -0700 Subject: xen/evtchn: don't do unbind_from_irqhandler under spinlock unbind_from_irqhandler can end up doing /proc operations, which can't happen under a spinlock. So before removing the IRQ handler, disable the irq under the port_user lock (masking the underlying event channel and making sure the irq handler isn't running concurrently and won't start running), then remove the handler without the lock. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index f79ac5ca3793..6a3a12945d02 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -375,10 +375,12 @@ static long evtchn_ioctl(struct file *file, break; } - evtchn_unbind_from_user(u, unbind.port); + disable_irq(irq_from_evtchn(unbind.port)); spin_unlock_irq(&port_user_lock); + evtchn_unbind_from_user(u, unbind.port); + rc = 0; break; } @@ -484,11 +486,18 @@ static int evtchn_release(struct inode *inode, struct file *filp) if (get_port_user(i) != u) continue; - evtchn_unbind_from_user(get_port_user(i), i); + disable_irq(irq_from_evtchn(i)); } spin_unlock_irq(&port_user_lock); + for (i = 0; i < NR_EVENT_CHANNELS; i++) { + if (get_port_user(i) != u) + continue; + + evtchn_unbind_from_user(get_port_user(i), i); + } + kfree(u->name); kfree(u); -- cgit v1.2.3 From 376d908f52427591cef4acd172db9c3ef28676ec Mon Sep 17 00:00:00 2001 From: Bastian Blank Date: Fri, 28 May 2010 15:43:49 -0700 Subject: xen/evtchn: Fix name of Xen event-channel device The Xen event-channel device is named evtchn in the kernel but always used as /dev/xen/evtchn in userspace. This patch fixes the name. Signed-off-by: Bastian Blank Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 6a3a12945d02..68119f6324d4 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -517,7 +517,7 @@ static const struct file_operations evtchn_fops = { static struct miscdevice evtchn_miscdev = { .minor = MISC_DYNAMIC_MINOR, - .name = "evtchn", + .name = "xen/evtchn", .fops = &evtchn_fops, }; static int __init evtchn_init(void) -- cgit v1.2.3 From 70697d540c0598ad023a391d4c895044db9a6624 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 5 Oct 2010 11:13:44 -0700 Subject: xen/evtchn: add missing static Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 68119f6324d4..f3594ec2ee33 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -99,7 +99,7 @@ static inline void set_port_enabled(unsigned port, bool enabled) port_user[port] &= ~1; } -irqreturn_t evtchn_interrupt(int irq, void *data) +static irqreturn_t evtchn_interrupt(int irq, void *data) { unsigned int port = (unsigned long)data; struct per_user_data *u; -- cgit v1.2.3 From 2f56f56ad991edd51ffd0baf1182245ee1277a04 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 27 Oct 2010 20:59:49 -0700 Subject: Revert "ceph: update issue_seq on cap grant" This reverts commit d91f2438d881514e4a923fd786dbd94b764a9440. The intent of issue_seq is to distinguish between mds->client messages that (re)create the cap and those that do not, which means we should _only_ be updating that value in the create paths. By updating it in handle_cap_grant, we reset it to zero, which then breaks release. The larger question is what workload/problem made me think it should be updated here... Signed-off-by: Sage Weil --- fs/ceph/caps.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 98ab13e2b71d..6e0942f33dd8 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2273,8 +2273,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, { struct ceph_inode_info *ci = ceph_inode(inode); int mds = session->s_mds; - unsigned seq = le32_to_cpu(grant->seq); - unsigned issue_seq = le32_to_cpu(grant->issue_seq); + int seq = le32_to_cpu(grant->seq); int newcaps = le32_to_cpu(grant->caps); int issued, implemented, used, wanted, dirty; u64 size = le64_to_cpu(grant->size); @@ -2286,8 +2285,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, int revoked_rdcache = 0; int queue_invalidate = 0; - dout("handle_cap_grant inode %p cap %p mds%d seq %u/%u %s\n", - inode, cap, mds, seq, issue_seq, ceph_cap_string(newcaps)); + dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", + inode, cap, mds, seq, ceph_cap_string(newcaps)); dout(" size %llu max_size %llu, i_size %llu\n", size, max_size, inode->i_size); @@ -2383,7 +2382,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, } cap->seq = seq; - cap->issue_seq = issue_seq; /* file layout may have changed */ ci->i_layout = grant->layout; -- cgit v1.2.3 From 313e74412105c670ff8900ec8099a3a5df1fa83c Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 28 Oct 2010 15:39:02 +0400 Subject: xen: xenfs: privcmd: check put_user() return code put_user() may fail. In this case propagate error code from privcmd_ioctl_mmap_batch(). Signed-off-by: Vasiliy Kulikov Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/privcmd.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c index f80be7f6eb95..2eb04c842511 100644 --- a/drivers/xen/xenfs/privcmd.c +++ b/drivers/xen/xenfs/privcmd.c @@ -266,9 +266,7 @@ static int mmap_return_errors(void *data, void *state) xen_pfn_t *mfnp = data; struct mmap_batch_state *st = state; - put_user(*mfnp, st->user++); - - return 0; + return put_user(*mfnp, st->user++); } static struct vm_operations_struct privcmd_vm_ops; @@ -323,10 +321,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata) up_write(&mm->mmap_sem); if (state.err > 0) { - ret = 0; - state.user = m.arr; - traverse_pages(m.num, sizeof(xen_pfn_t), + ret = traverse_pages(m.num, sizeof(xen_pfn_t), &pagelist, mmap_return_errors, &state); } -- cgit v1.2.3 From df9f86faf3ee610527ed02031fe7dd3c8b752e44 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 1 Nov 2010 15:49:23 -0700 Subject: ceph: fix small seq message skipping If the client gets out of sync with the server message sequence number, we normally skip low seq messages (ones we already received). The skip code was also incrementing the expected seq, such that all subsequent messages also appeared old and got skipped, and an eventual timeout on the osd connection. This resulted in some lagging requests and console messages like [233480.882885] ceph: skipping osd22 10.138.138.13:6804 seq 2016, expected 2017 [233480.882919] ceph: skipping osd22 10.138.138.13:6804 seq 2017, expected 2018 [233480.882963] ceph: skipping osd22 10.138.138.13:6804 seq 2018, expected 2019 [233480.883488] ceph: skipping osd22 10.138.138.13:6804 seq 2019, expected 2020 [233485.219558] ceph: skipping osd22 10.138.138.13:6804 seq 2020, expected 2021 [233485.906595] ceph: skipping osd22 10.138.138.13:6804 seq 2021, expected 2022 [233490.379536] ceph: skipping osd22 10.138.138.13:6804 seq 2022, expected 2023 [233495.523260] ceph: skipping osd22 10.138.138.13:6804 seq 2023, expected 2024 [233495.923194] ceph: skipping osd22 10.138.138.13:6804 seq 2024, expected 2025 [233500.534614] ceph: tid 6023602 timed out on osd22, will reset osd Reported-by: Theodore Ts'o Signed-off-by: Sage Weil --- net/ceph/messenger.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0e8157ee5d43..d379abf873bc 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1532,14 +1532,13 @@ static int read_partial_message(struct ceph_connection *con) /* verify seq# */ seq = le64_to_cpu(con->in_hdr.seq); if ((s64)seq - (s64)con->in_seq < 1) { - pr_info("skipping %s%lld %s seq %lld, expected %lld\n", + pr_info("skipping %s%lld %s seq %lld expected %lld\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr), seq, con->in_seq + 1); con->in_base_pos = -front_len - middle_len - data_len - sizeof(m->footer); con->in_tag = CEPH_MSGR_TAG_READY; - con->in_seq++; return 0; } else if ((s64)seq - (s64)con->in_seq > 1) { pr_err("read_partial_message bad seq %lld expected %lld\n", -- cgit v1.2.3 From c46e0079cec40b49fbdb86a088cfd50b250fef47 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 3 Nov 2010 15:04:45 +0800 Subject: ASoC: Fix snd_soc_register_dais error handling kzalloc for dai may fail at any iteration of the for loop, thus properly unregister already registered DAIs before return error. The error handling code in snd_soc_register_dais() already ensure all the DAIs are unregistered before return error, we can remove the error handling code to unregister DAIs in snd_soc_register_codec(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 614a8b30d87b..441285ade024 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3043,8 +3043,10 @@ int snd_soc_register_dais(struct device *dev, for (i = 0; i < count; i++) { dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); - if (dai == NULL) - return -ENOMEM; + if (dai == NULL) { + ret = -ENOMEM; + goto err; + } /* create DAI component name */ dai->name = fmt_multiple_name(dev, &dai_drv[i]); @@ -3263,9 +3265,6 @@ int snd_soc_register_codec(struct device *dev, return 0; error: - for (i--; i >= 0; i--) - snd_soc_unregister_dai(dev); - if (codec->reg_cache) kfree(codec->reg_cache); kfree(codec->name); -- cgit v1.2.3 From 233538501f707b0176f09af7039fec1e3fcac6e7 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 2 Nov 2010 15:50:32 +0100 Subject: ASoC: OMAP: fix OMAP1 compilation problem In the new code introduced with commit cf4c87abe238ec17cd0255b4e21abd949d7f811e, "OMAP: McBSP: implement McBSP CLKR and FSR signal muxing via mach-omap2/mcbsp.c", the way omap1 build is supposed to bypass omap2 specific functionality doesn't optimize out all omap2 specific stuff. This breaks linking phase for omap1 machines, giving "undefined reference to `omap2_mcbsp1_mux_clkr_src'" and "undefined reference to `omap2_mcbsp1_mux_fsr_src'" errors. Fix it. Created and tested against linux-2.6.37-rc1. Signed-off-by: Janusz Krzysztofik Acked-by: Mark Brown Acked-by: Paul Walmsley Acked-by: Jarkko Nikula Signed-off-by: Liam Girdwood --- sound/soc/omap/omap-mcbsp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index d211c9fa5a91..7e84f24b9a88 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -644,15 +644,23 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_CLKR_SRC_CLKR: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR); break; case OMAP_MCBSP_CLKR_SRC_CLKX: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX); break; case OMAP_MCBSP_FSR_SRC_FSR: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR); break; case OMAP_MCBSP_FSR_SRC_FSX: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX); break; default: -- cgit v1.2.3 From 74a557e27ff86a5a1f8d5f24c178c70b98367b12 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Nov 2010 09:37:06 -0400 Subject: ASoC: Check return value of strict_strtoul() in WM8962 strict_strtoul() has been made __must_check so do so. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8962.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 894d0cd3aa9b..e8092745a207 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3500,8 +3500,11 @@ static ssize_t wm8962_beep_set(struct device *dev, { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; + int ret; - strict_strtol(buf, 10, &time); + ret = strict_strtol(buf, 10, &time); + if (ret != 0) + return ret; input_event(wm8962->beep, EV_SND, SND_TONE, time); -- cgit v1.2.3 From add330ec29cb00b26cf45ffb4773bb9094a48368 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Nov 2010 17:05:40 +0100 Subject: ASoC i.MX eukrea tlv320: Fix for multicomponent Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/eukrea-tlv320.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c index b59675257ce5..dd4fffdbd177 100644 --- a/sound/soc/imx/eukrea-tlv320.c +++ b/sound/soc/imx/eukrea-tlv320.c @@ -34,8 +34,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | @@ -79,10 +79,10 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = { static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", - .codec_dai = "tlv320aic23-hifi", + .codec_dai_name = "tlv320aic23-hifi", .platform_name = "imx-pcm-audio.0", .codec_name = "tlv320aic23-codec.0-001a", - .cpu_dai = "imx-ssi.0", + .cpu_dai_name = "imx-ssi.0", .ops = &eukrea_tlv320_snd_ops, }; -- cgit v1.2.3 From bf0199b7a5085e8d1908d2b0a9c530ed8d142fb8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Nov 2010 17:05:41 +0100 Subject: ASoC i.MX phycore ac97: remove unnecessary includes Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/phycore-ac97.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c index 6a65dd705519..cf46a17d6925 100644 --- a/sound/soc/imx/phycore-ac97.c +++ b/sound/soc/imx/phycore-ac97.c @@ -20,9 +20,6 @@ #include #include -#include "../codecs/wm9712.h" -#include "imx-ssi.h" - static struct snd_soc_card imx_phycore; static struct snd_soc_ops imx_phycore_hifi_ops = { -- cgit v1.2.3 From f562be51fe9021c913e661c46681cb5bae70f369 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Nov 2010 17:05:42 +0100 Subject: ASoC i.MX: register dma audio device We have two different transfer methods on i.MX: FIQ and DMA. Since the merge of the ASoC multicomponent support the DMA device is lost. Add it again. Also, imx_ssi_dai_probe has to be called for !AC97 aswell. Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/imx-ssi.c | 44 +++++++++++++++++++++++++++++--------------- sound/soc/imx/imx-ssi.h | 1 + 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index d4bd345b0a8d..d2d98c75ee8a 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -439,7 +439,22 @@ void imx_pcm_free(struct snd_pcm *pcm) } EXPORT_SYMBOL_GPL(imx_pcm_free); +static int imx_ssi_dai_probe(struct snd_soc_dai *dai) +{ + struct imx_ssi *ssi = dev_get_drvdata(dai->dev); + uint32_t val; + + snd_soc_dai_set_drvdata(dai, ssi); + + val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | + SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); + writel(val, ssi->base + SSI_SFCSR); + + return 0; +} + static struct snd_soc_dai_driver imx_ssi_dai = { + .probe = imx_ssi_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, @@ -455,20 +470,6 @@ static struct snd_soc_dai_driver imx_ssi_dai = { .ops = &imx_ssi_pcm_dai_ops, }; -static int imx_ssi_dai_probe(struct snd_soc_dai *dai) -{ - struct imx_ssi *ssi = dev_get_drvdata(dai->dev); - uint32_t val; - - snd_soc_dai_set_drvdata(dai, ssi); - - val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | - SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); - writel(val, ssi->base + SSI_SFCSR); - - return 0; -} - static struct snd_soc_dai_driver imx_ac97_dai = { .probe = imx_ssi_dai_probe, .ac97_control = 1, @@ -677,7 +678,17 @@ static int imx_ssi_probe(struct platform_device *pdev) goto failed_register; } - ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id); + ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id); + if (!ssi->soc_platform_pdev_fiq) + goto failed_pdev_fiq_alloc; + platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi); + ret = platform_device_add(ssi->soc_platform_pdev_fiq); + if (ret) { + dev_err(&pdev->dev, "failed to add platform device\n"); + goto failed_pdev_fiq_add; + } + + ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id); if (!ssi->soc_platform_pdev) goto failed_pdev_alloc; platform_set_drvdata(ssi->soc_platform_pdev, ssi); @@ -692,6 +703,9 @@ static int imx_ssi_probe(struct platform_device *pdev) failed_pdev_add: platform_device_put(ssi->soc_platform_pdev); 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); failed_register: failed_ac97: diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index 53b780d9b2b0..4fc17da11866 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -212,6 +212,7 @@ struct imx_ssi { int enabled; struct platform_device *soc_platform_pdev; + struct platform_device *soc_platform_pdev_fiq; }; struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, -- cgit v1.2.3 From bf974a0d77a318a733a47c18a47fa6ff8960c361 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Nov 2010 17:05:43 +0100 Subject: ASoC i.MX: switch to new DMA api Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/imx-pcm-dma-mx2.c | 221 ++++++++++++++++++---------------------- sound/soc/imx/imx-ssi.h | 3 + 2 files changed, 101 insertions(+), 123 deletions(-) diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index fd493ee1428e..671ef8dd524c 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,165 +28,146 @@ #include #include -#include +#include #include "imx-ssi.h" struct imx_pcm_runtime_data { - int sg_count; - struct scatterlist *sg_list; - int period; + int period_bytes; int periods; - unsigned long dma_addr; int dma; - struct snd_pcm_substream *substream; unsigned long offset; unsigned long size; - unsigned long period_cnt; void *buf; int period_time; + struct dma_async_tx_descriptor *desc; + struct dma_chan *dma_chan; + struct imx_dma_data dma_data; }; -/* Called by the DMA framework when a period has elapsed */ -static void imx_ssi_dma_progression(int channel, void *data, - struct scatterlist *sg) +static void audio_dma_irq(void *data) { - struct snd_pcm_substream *substream = data; + struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - if (!sg) - return; - - runtime = iprtd->substream->runtime; + iprtd->offset += iprtd->period_bytes; + iprtd->offset %= iprtd->period_bytes * iprtd->periods; - iprtd->offset = sg->dma_address - runtime->dma_addr; - - snd_pcm_period_elapsed(iprtd->substream); + snd_pcm_period_elapsed(substream); } -static void imx_ssi_dma_callback(int channel, void *data) +static bool filter(struct dma_chan *chan, void *param) { - pr_err("%s shouldn't be called\n", __func__); -} + struct imx_pcm_runtime_data *iprtd = param; -static void snd_imx_dma_err_callback(int channel, void *data, int err) -{ - struct snd_pcm_substream *substream = data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct imx_pcm_dma_params *dma_params = - snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int ret; + if (!imx_dma_is_general_purpose(chan)) + return false; - pr_err("DMA timeout on channel %d -%s%s%s%s\n", - channel, - err & IMX_DMA_ERR_BURST ? " burst" : "", - err & IMX_DMA_ERR_REQUEST ? " request" : "", - err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", - err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); + chan->private = &iprtd->dma_data; - imx_dma_disable(iprtd->dma); - ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, - IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MODE_WRITE : DMA_MODE_READ); - if (!ret) - imx_dma_enable(iprtd->dma); + return true; } -static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) +static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; + struct dma_slave_config slave_config; + dma_cap_mask_t mask; + enum dma_slave_buswidth buswidth; int ret; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); - if (iprtd->dma < 0) { - pr_err("Failed to claim the audio DMA\n"); - return -ENODEV; - } + iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI; + iprtd->dma_data.priority = DMA_PRIO_HIGH; + iprtd->dma_data.dma_request = dma_params->dma; - ret = imx_dma_setup_handlers(iprtd->dma, - imx_ssi_dma_callback, - snd_imx_dma_err_callback, substream); - if (ret) - goto out; + /* Try to grab a DMA channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); + if (!iprtd->dma_chan) + return -EINVAL; - ret = imx_dma_setup_progression_handler(iprtd->dma, - imx_ssi_dma_progression); - if (ret) { - pr_err("Failed to setup the DMA handler\n"); - goto out; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S24_LE: + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + return 0; } - ret = imx_dma_config_channel(iprtd->dma, - IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, - dma_params->dma, 1); - if (ret < 0) { - pr_err("Cannot configure DMA channel: %d\n", ret); - goto out; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_TO_DEVICE; + slave_config.dst_addr = dma_params->dma_addr; + slave_config.dst_addr_width = buswidth; + slave_config.dst_maxburst = dma_params->burstsize; + } else { + slave_config.direction = DMA_FROM_DEVICE; + slave_config.src_addr = dma_params->dma_addr; + slave_config.src_addr_width = buswidth; + slave_config.src_maxburst = dma_params->burstsize; } - imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); + ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); + if (ret) + return ret; return 0; -out: - imx_dma_free(iprtd->dma); - return ret; } static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int i; unsigned long dma_addr; + struct dma_chan *chan; + struct imx_pcm_dma_params *dma_params; + int ret; - imx_ssi_dma_alloc(substream); + dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + ret = imx_ssi_dma_alloc(substream, params); + if (ret) + return ret; + chan = iprtd->dma_chan; iprtd->size = params_buffer_bytes(params); iprtd->periods = params_periods(params); - iprtd->period = params_period_bytes(params); + iprtd->period_bytes = params_period_bytes(params); iprtd->offset = 0; iprtd->period_time = HZ / (params_rate(params) / params_period_size(params)); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - if (iprtd->sg_count != iprtd->periods) { - kfree(iprtd->sg_list); - - iprtd->sg_list = kcalloc(iprtd->periods + 1, - sizeof(struct scatterlist), GFP_KERNEL); - if (!iprtd->sg_list) - return -ENOMEM; - iprtd->sg_count = iprtd->periods + 1; - } - - sg_init_table(iprtd->sg_list, iprtd->sg_count); dma_addr = runtime->dma_addr; - for (i = 0; i < iprtd->periods; i++) { - iprtd->sg_list[i].page_link = 0; - iprtd->sg_list[i].offset = 0; - iprtd->sg_list[i].dma_address = dma_addr; - iprtd->sg_list[i].length = iprtd->period; - dma_addr += iprtd->period; + iprtd->buf = (unsigned int *)substream->dma_buffer.area; + + iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, + iprtd->period_bytes * iprtd->periods, + iprtd->period_bytes, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!iprtd->desc) { + dev_err(&chan->dev->device, "cannot prepare slave dma\n"); + return -EINVAL; } - /* close the loop */ - iprtd->sg_list[iprtd->sg_count - 1].offset = 0; - iprtd->sg_list[iprtd->sg_count - 1].length = 0; - iprtd->sg_list[iprtd->sg_count - 1].page_link = - ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; + iprtd->desc->callback = audio_dma_irq; + iprtd->desc->callback_param = substream; + return 0; } @@ -194,41 +176,21 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - if (iprtd->dma >= 0) { - imx_dma_free(iprtd->dma); - iprtd->dma = -EINVAL; + if (iprtd->dma_chan) { + dma_release_channel(iprtd->dma_chan); + iprtd->dma_chan = NULL; } - kfree(iprtd->sg_list); - iprtd->sg_list = NULL; - return 0; } static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int err; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - iprtd->substream = substream; - iprtd->buf = (unsigned int *)substream->dma_buffer.area; - iprtd->period_cnt = 0; - - pr_debug("%s: buf: %p period: %d periods: %d\n", - __func__, iprtd->buf, iprtd->period, iprtd->periods); - - err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, - IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MODE_WRITE : DMA_MODE_READ); - if (err) - return err; - return 0; } @@ -241,14 +203,14 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - imx_dma_enable(iprtd->dma); + dmaengine_submit(iprtd->desc); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - imx_dma_disable(iprtd->dma); + dmaengine_terminate_all(iprtd->dma_chan); break; default: @@ -263,6 +225,9 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; + pr_debug("%s: %ld %ld\n", __func__, iprtd->offset, + bytes_to_frames(substream->runtime, iprtd->offset)); + return bytes_to_frames(substream->runtime, iprtd->offset); } @@ -279,7 +244,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { .channels_max = 2, .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, - .period_bytes_max = 16 * 1024, + .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, .periods_max = 255, .fifo_size = 0, @@ -304,11 +269,23 @@ static int snd_imx_open(struct snd_pcm_substream *substream) } snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + + return 0; +} + +static int snd_imx_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + kfree(iprtd); + return 0; } static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, + .close = snd_imx_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .hw_free = snd_imx_pcm_hw_free, @@ -340,7 +317,6 @@ static struct platform_driver imx_pcm_driver = { .name = "imx-pcm-audio", .owner = THIS_MODULE, }, - .probe = imx_soc_platform_probe, .remove = __devexit_p(imx_soc_platform_remove), }; @@ -356,4 +332,3 @@ static void __exit snd_imx_pcm_exit(void) platform_driver_unregister(&imx_pcm_driver); } module_exit(snd_imx_pcm_exit); - diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index 4fc17da11866..a4406a134892 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -185,6 +185,9 @@ #define DRV_NAME "imx-ssi" +#include +#include + struct imx_pcm_dma_params { int dma; unsigned long dma_addr; -- cgit v1.2.3 From 6424dca23e6b5a2f7a19a69cf7c0990b11717b00 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 Nov 2010 17:05:44 +0100 Subject: phycore-ac97: add ac97 to cardname We have different codecs on the pcm038 (ac97 wm9712 and mc13783). To make alsactl restore work correctly these should have different names. Signed-off-by: Sascha Hauer Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/phycore-ac97.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c index cf46a17d6925..39f23734781a 100644 --- a/sound/soc/imx/phycore-ac97.c +++ b/sound/soc/imx/phycore-ac97.c @@ -38,7 +38,7 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { }; static struct snd_soc_card imx_phycore = { - .name = "PhyCORE-audio", + .name = "PhyCORE-ac97-audio", .dai_link = imx_phycore_dai_ac97, .num_links = ARRAY_SIZE(imx_phycore_dai_ac97), }; -- cgit v1.2.3 From 71a295602ed967fa22d96d57a2e38bb86de24db7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Nov 2010 13:50:48 -0400 Subject: ASoC: Lock the CODEC in PXA external jack controls When doing anything with the system, especially DAPM, we need to hold the CODEC mutex. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/pxa/corgi.c | 5 +++++ sound/soc/pxa/magician.c | 4 ++++ sound/soc/pxa/poodle.c | 5 +++++ sound/soc/pxa/spitz.c | 5 +++++ sound/soc/pxa/tosa.c | 5 +++++ 5 files changed, 24 insertions(+) diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 97e9423615c9..f451acd4935b 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -100,8 +100,13 @@ static int corgi_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ corgi_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index b8207ced4072..5ef0526924b9 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -72,9 +72,13 @@ static int magician_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ magician_ext_control(codec); + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index af84ee9c5e11..84edd0385a21 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -77,8 +77,13 @@ static int poodle_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ poodle_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index f470f360f4dd..0b30d7de24ec 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -108,8 +108,13 @@ static int spitz_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ spitz_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 73d0edd8ded9..7b983f935454 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -81,8 +81,13 @@ static int tosa_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ tosa_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } -- cgit v1.2.3 From 197ebd4053c42351e3737d83aebb33ed97ed2dd8 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 5 Nov 2010 10:36:24 +0000 Subject: ASoC: WM8776: Removed unneeded struct member The member reg_cache is not used at all and therefore it should be removed. This member was usually needed for older versions of ASoC that did not handle caching automatically and had to be done in the driver itself. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm8776.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 04182c464e35..0132a27140ae 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -34,7 +34,6 @@ /* codec private data */ struct wm8776_priv { enum snd_soc_control_type control_type; - u16 reg_cache[WM8776_CACHEREGNUM]; int sysclk[2]; }; -- cgit v1.2.3 From d8b16b3d1c9d8d9124d647d05797383d35e2d645 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 6 Nov 2010 12:41:16 -0700 Subject: ceph: fix bad pointer dereference in ceph_fill_trace We dereference *in a few lines down, but only set it on rename. It is apparently pretty rare for this to trigger, but I have been hitting it with a clustered MDSs. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1d6a45b5a04c..cd0432c03d2f 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1055,7 +1055,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, ininfo = rinfo->targeti.in; vino.ino = le64_to_cpu(ininfo->ino); vino.snap = le64_to_cpu(ininfo->snapid); - if (!dn->d_inode) { + in = dn->d_inode; + if (!in) { in = ceph_get_inode(sb, vino); if (IS_ERR(in)) { pr_err("fill_trace bad get_inode " -- cgit v1.2.3 From 7421ab8041d98363edfb85955fa3b9849ffae366 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 7 Nov 2010 09:07:15 -0800 Subject: ceph: fix open for write on clustered mds Normally when we open a file we already have a cap, and simply update the wanted set. However, if we open a file for write, but don't have an auth cap, that doesn't work; we need to open a new cap with the auth MDS. Only reuse existing caps if we are opening for read or the existing cap is auth. Signed-off-by: Sage Weil --- fs/ceph/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index e77c28cf3690..87ee944724f8 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -154,11 +154,13 @@ int ceph_open(struct inode *inode, struct file *file) } /* - * No need to block if we have any caps. Update wanted set + * No need to block if we have caps on the auth MDS (for + * write) or any MDS (for read). Update wanted set * asynchronously. */ spin_lock(&inode->i_lock); - if (__ceph_is_any_real_caps(ci)) { + if (__ceph_is_any_real_caps(ci) && + (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) { int mds_wanted = __ceph_caps_mds_wanted(ci); int issued = __ceph_caps_issued(ci, NULL); -- cgit v1.2.3 From 912a9b0319a8eb9e0834b19a25e01013ab2d6a9f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 7 Nov 2010 09:37:25 -0800 Subject: ceph: only let auth caps update max_size Only the auth MDS has a meaningful max_size value for us, so only update it in fill_inode if we're being issued an auth cap. Otherwise, a random stat result from a non-auth MDS can clobber a meaningful max_size, get the client<->mds cap state out of sync, and make writes hang. Specifically, even if the client re-requests a larger max_size (which it will), the MDS won't respond because as far as it knows we already have a sufficiently large value. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index cd0432c03d2f..0a49ffde5bcb 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -606,7 +606,14 @@ static int fill_inode(struct inode *inode, le32_to_cpu(info->time_warp_seq), &ctime, &mtime, &atime); - ci->i_max_size = le64_to_cpu(info->max_size); + /* only update max_size on auth cap */ + if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && + ci->i_max_size != le64_to_cpu(info->max_size)) { + dout("max_size %lld -> %llu\n", ci->i_max_size, + le64_to_cpu(info->max_size)); + ci->i_max_size = le64_to_cpu(info->max_size); + } + ci->i_layout = info->layout; inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; -- cgit v1.2.3 From feb4cc9bb433bf1491ac5ffbba133f3258dacf06 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 7 Nov 2010 09:39:00 -0800 Subject: ceph: re-request max_size if cap auth changes If the auth cap migrates to another MDS, clear requested_max_size so that we resend any pending max_size increase requests. This fixes potential hangs on writes that extend a file and race with an cap migration between MDSs. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 6e0942f33dd8..04b207b0c842 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2689,6 +2689,11 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, NULL /* no caps context */); try_flush_caps(inode, session, NULL); up_read(&mdsc->snap_rwsem); + + /* make sure we re-request max_size, if necessary */ + spin_lock(&inode->i_lock); + ci->i_requested_max_size = 0; + spin_unlock(&inode->i_lock); } /* -- cgit v1.2.3 From cd045cb42a266882ac24bc21a3a8d03683c72954 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 4 Nov 2010 11:05:05 -0700 Subject: ceph: fix rdcache_gen usage and invalidate We used to use rdcache_gen to indicate whether we "might" have cached pages. Now we just look at the mapping to determine that. However, some old behavior remains from that transition. First, rdcache_gen == 0 no longer means we have no pages. That can happen at any time (presumably when we carry FILE_CACHE). We should not reset it to zero, and we should not check that it is zero. That means that the only purpose for rdcache_revoking is to resolve races between new issues of FILE_CACHE and an async invalidate. If they are equal, we should invalidate. On success, we decrement rdcache_revoking, so that it is no longer equal to rdcache_gen. Similarly, if we success in doing a sync invalidate, set revoking = gen - 1. (This is a small optimization to avoid doing unnecessary invalidate work and does not affect correctness.) Signed-off-by: Sage Weil --- fs/ceph/caps.c | 4 ++-- fs/ceph/inode.c | 16 +++++++--------- fs/ceph/super.h | 4 +--- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 04b207b0c842..60d27bc9eb83 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1430,8 +1430,8 @@ static int try_nonblocking_invalidate(struct inode *inode) invalidating_gen == ci->i_rdcache_gen) { /* success. */ dout("try_nonblocking_invalidate %p success\n", inode); - ci->i_rdcache_gen = 0; - ci->i_rdcache_revoking = 0; + /* save any racing async invalidate some trouble */ + ci->i_rdcache_revoking = ci->i_rdcache_gen - 1; return 0; } dout("try_nonblocking_invalidate %p failed\n", inode); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 0a49ffde5bcb..5a9f907b805e 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1394,11 +1394,8 @@ static void ceph_invalidate_work(struct work_struct *work) spin_lock(&inode->i_lock); dout("invalidate_pages %p gen %d revoking %d\n", inode, ci->i_rdcache_gen, ci->i_rdcache_revoking); - if (ci->i_rdcache_gen == 0 || - ci->i_rdcache_revoking != ci->i_rdcache_gen) { - BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen); + if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { /* nevermind! */ - ci->i_rdcache_revoking = 0; spin_unlock(&inode->i_lock); goto out; } @@ -1408,15 +1405,16 @@ static void ceph_invalidate_work(struct work_struct *work) ceph_invalidate_nondirty_pages(inode->i_mapping); spin_lock(&inode->i_lock); - if (orig_gen == ci->i_rdcache_gen) { + if (orig_gen == ci->i_rdcache_gen && + orig_gen == ci->i_rdcache_revoking) { dout("invalidate_pages %p gen %d successful\n", inode, ci->i_rdcache_gen); - ci->i_rdcache_gen = 0; - ci->i_rdcache_revoking = 0; + ci->i_rdcache_revoking--; check = 1; } else { - dout("invalidate_pages %p gen %d raced, gen now %d\n", - inode, orig_gen, ci->i_rdcache_gen); + dout("invalidate_pages %p gen %d raced, now %d revoking %d\n", + inode, orig_gen, ci->i_rdcache_gen, + ci->i_rdcache_revoking); } spin_unlock(&inode->i_lock); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 1886294e12f7..7f01728a4657 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -293,9 +293,7 @@ struct ceph_inode_info { int i_rd_ref, i_rdcache_ref, i_wr_ref; int i_wrbuffer_ref, i_wrbuffer_ref_head; u32 i_shared_gen; /* increment each time we get FILE_SHARED */ - u32 i_rdcache_gen; /* we increment this each time we get - FILE_CACHE. If it's non-zero, we - _may_ have cached pages. */ + u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */ struct list_head i_unsafe_writes; /* uncommitted sync writes */ -- cgit v1.2.3 From cb4276cca4695670916a82e359f2e3776f0a9138 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 8 Nov 2010 07:28:52 -0800 Subject: ceph: fix uid/gid on resent mds requests MDS requests can be rebuilt and resent in non-process context, but were filling in uid/gid from current_fsuid/gid. Put that information in the request struct on request setup. This fixes incorrect (and root) uid/gid getting set for requests that are forwarded between MDSs, usually due to metadata migrations. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 7 +++++-- fs/ceph/mds_client.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 3142b15940c2..d22fbbef1959 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -529,6 +529,9 @@ static void __register_request(struct ceph_mds_client *mdsc, ceph_mdsc_get_request(req); __insert_request(mdsc, req); + req->r_uid = current_fsuid(); + req->r_gid = current_fsgid(); + if (dir) { struct ceph_inode_info *ci = ceph_inode(dir); @@ -1588,8 +1591,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch); head->op = cpu_to_le32(req->r_op); - head->caller_uid = cpu_to_le32(current_fsuid()); - head->caller_gid = cpu_to_le32(current_fsgid()); + head->caller_uid = cpu_to_le32(req->r_uid); + head->caller_gid = cpu_to_le32(req->r_gid); head->args = req->r_args; ceph_encode_filepath(&p, end, ino1, path1); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index d66d63c72355..9341fd4f1432 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -170,6 +170,8 @@ struct ceph_mds_request { union ceph_mds_request_args r_args; int r_fmode; /* file mode, if expecting cap */ + uid_t r_uid; + gid_t r_gid; /* for choosing which mds to send this request to */ int r_direct_mode; -- cgit v1.2.3 From 1ebd0061ededeb8b495360a772d0b885dd3e036e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 8 Nov 2010 13:24:58 +0800 Subject: ASoC: Return proper error if snd_soc_register_dais fails in psc_i2s_of_probe Signed-off-by: Axel Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 74ffed41340f..9018fa5bf0db 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -160,7 +160,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op, rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); - return 0; + return rc; } psc_dma = dev_get_drvdata(&op->dev); -- cgit v1.2.3 From b0fc7b840926654a3a6eaf0f41f3a4da33441d3d Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Mon, 8 Nov 2010 13:14:51 +0100 Subject: ASoC: s3c24xx: Fix compilation problem for mini2440 When make mini2440_defconfig compilation end with undefined references to DMA functions. There was missing selection for S3C2410_DMA when compile ASoC audio for S3C24xx CPU. Tested on mini2440 board. Signed-off-by: Marek Belisko Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 8a6b53ccd203..d85bf8a0abb2 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -2,6 +2,7 @@ config SND_S3C24XX_SOC tristate "SoC Audio for the Samsung S3CXXXX chips" depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 select S3C64XX_DMA if ARCH_S3C64XX + select S3C2410_DMA if ARCH_S3C2410 help Say Y or M if you want to add support for codecs attached to the S3C24XX AC97 or I2S interfaces. You will also need to -- cgit v1.2.3 From 8bd59e0188c04f6540f00e13f633f22e4804ce06 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 8 Nov 2010 09:23:12 -0800 Subject: ceph: fix version check on racing inode updates We may get updates on the same inode from multiple MDSs; generally we only pay attention if the update is newer than what we already have. The exception is when an MDS sense unstable information, in which case we always update. The old > check got this wrong when our version was odd (e.g. 3) and the reply version was even (e.g. 2): the older stale (v2) info would be applied. Fixed and clarified the comment. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 5a9f907b805e..425c5b1f944e 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -567,12 +567,17 @@ static int fill_inode(struct inode *inode, /* * provided version will be odd if inode value is projected, - * even if stable. skip the update if we have a newer info - * (e.g., due to inode info racing form multiple MDSs), or if - * we are getting projected (unstable) inode info. + * even if stable. skip the update if we have newer stable + * info (ours>=theirs, e.g. due to racing mds replies), unless + * we are getting projected (unstable) info (in which case the + * version is odd, and we want ours>theirs). + * us them + * 2 2 skip + * 3 2 skip + * 3 3 update */ if (le64_to_cpu(info->version) > 0 && - (ci->i_version & ~1) > le64_to_cpu(info->version)) + (ci->i_version & ~1) >= le64_to_cpu(info->version)) goto no_change; issued = __ceph_caps_issued(ci, &implemented); -- cgit v1.2.3 From d8672d64b88cdb7aa8139fb6d218f40b8cbf60af Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 8 Nov 2010 09:24:34 -0800 Subject: ceph: fix update of ctime from MDS The client can have a newer ctime than the MDS due to AUTH_EXCL and XATTR_EXCL caps as well; update the check in ceph_fill_file_time appropriately. This fixes cases where ctime/mtime goes backward under the right sequence of local updates (e.g. chmod) and mds replies (e.g. subsequent stat that goes to the MDS). Signed-off-by: Sage Weil --- fs/ceph/inode.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 425c5b1f944e..7bc0fbd26af2 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -471,7 +471,9 @@ void ceph_fill_file_time(struct inode *inode, int issued, if (issued & (CEPH_CAP_FILE_EXCL| CEPH_CAP_FILE_WR| - CEPH_CAP_FILE_BUFFER)) { + CEPH_CAP_FILE_BUFFER| + CEPH_CAP_AUTH_EXCL| + CEPH_CAP_XATTR_EXCL)) { if (timespec_compare(ctime, &inode->i_ctime) > 0) { dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n", inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec, @@ -511,7 +513,7 @@ void ceph_fill_file_time(struct inode *inode, int issued, warn = 1; } } else { - /* we have no write caps; whatever the MDS says is true */ + /* we have no write|excl caps; whatever the MDS says is true */ if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) { inode->i_ctime = *ctime; inode->i_mtime = *mtime; -- cgit v1.2.3 From e98b6fed84d0f0155d7b398e0dfeac74c792f2d0 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 9 Nov 2010 12:24:53 -0800 Subject: ceph: fix comment, remove extraneous args The offset/length arguments aren't used. Signed-off-by: Sage Weil --- fs/ceph/file.c | 20 +++++++++----------- include/linux/ceph/libceph.h | 3 +-- net/ceph/pagevec.c | 3 +-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 87ee944724f8..603fd00af0a6 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -376,21 +376,19 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, dout("sync_read on file %p %llu~%u %s\n", file, off, len, (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); - if (file->f_flags & O_DIRECT) { - pages = ceph_get_direct_page_vector(data, num_pages, off, len); - - /* - * flush any page cache pages in this range. this - * will make concurrent normal and O_DIRECT io slow, - * but it will at least behave sensibly when they are - * in sequence. - */ - } else { + if (file->f_flags & O_DIRECT) + pages = ceph_get_direct_page_vector(data, num_pages); + else pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); - } if (IS_ERR(pages)) return PTR_ERR(pages); + /* + * flush any page cache pages in this range. this + * will make concurrent normal and sync io slow, + * but it will at least behave sensibly when they are + * in sequence. + */ ret = filemap_write_and_wait(inode->i_mapping); if (ret < 0) goto done; diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index f22b2e941686..9e76d35670d2 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -227,8 +227,7 @@ extern int ceph_open_session(struct ceph_client *client); extern void ceph_release_page_vector(struct page **pages, int num_pages); extern struct page **ceph_get_direct_page_vector(const char __user *data, - int num_pages, - loff_t off, size_t len); + int num_pages); extern void ceph_put_page_vector(struct page **pages, int num_pages); extern void ceph_release_page_vector(struct page **pages, int num_pages); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c index 54caf0687155..ac34feeb2b3a 100644 --- a/net/ceph/pagevec.c +++ b/net/ceph/pagevec.c @@ -13,8 +13,7 @@ * build a vector of user pages */ struct page **ceph_get_direct_page_vector(const char __user *data, - int num_pages, - loff_t off, size_t len) + int num_pages) { struct page **pages; int rc; -- cgit v1.2.3 From b7495fc2ff941db6a118a93ab8d61149e3f4cef8 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 9 Nov 2010 12:43:12 -0800 Subject: ceph: make page alignment explicit in osd interface We used to infer alignment of IOs within a page based on the file offset, which assumed they matched. This broke with direct IO that was not aligned to pages (e.g., 512-byte aligned IO). We were also trusting the alignment specified in the OSD reply, which could have been adjusted by the server. Explicitly specify the page alignment when setting up OSD IO requests. Signed-off-by: Sage Weil --- fs/ceph/addr.c | 6 +++--- fs/ceph/file.c | 26 +++++++++++++++++++++----- fs/ceph/inode.c | 2 +- include/linux/ceph/osd_client.h | 7 +++++-- net/ceph/osd_client.c | 22 ++++++++++++++-------- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 51bcc5ce3230..4aa857763037 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -204,7 +204,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, page->index << PAGE_CACHE_SHIFT, &len, ci->i_truncate_seq, ci->i_truncate_size, - &page, 1); + &page, 1, 0); if (err == -ENOENT) err = 0; if (err < 0) { @@ -287,7 +287,7 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, offset, &len, ci->i_truncate_seq, ci->i_truncate_size, - pages, nr_pages); + pages, nr_pages, 0); if (rc == -ENOENT) rc = 0; if (rc < 0) @@ -782,7 +782,7 @@ get_more_pages: snapc, do_sync, ci->i_truncate_seq, ci->i_truncate_size, - &inode->i_mtime, true, 1); + &inode->i_mtime, true, 1, 0); max_pages = req->r_num_pages; alloc_page_vec(fsc, req); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 603fd00af0a6..8d79b8912e31 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -282,11 +282,12 @@ int ceph_release(struct inode *inode, struct file *file) static int striped_read(struct inode *inode, u64 off, u64 len, struct page **pages, int num_pages, - int *checkeof) + int *checkeof, bool align_to_pages) { struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); u64 pos, this_len; + int io_align, page_align; int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */ int left, pages_left; int read; @@ -302,14 +303,19 @@ static int striped_read(struct inode *inode, page_pos = pages; pages_left = num_pages; read = 0; + io_align = off & ~PAGE_MASK; more: + if (align_to_pages) + page_align = (pos - io_align) & ~PAGE_MASK; + else + page_align = pos & ~PAGE_MASK; this_len = left; ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode), &ci->i_layout, pos, &this_len, ci->i_truncate_seq, ci->i_truncate_size, - page_pos, pages_left); + page_pos, pages_left, page_align); hit_stripe = this_len < left; was_short = ret >= 0 && ret < this_len; if (ret == -ENOENT) @@ -393,7 +399,8 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, if (ret < 0) goto done; - ret = striped_read(inode, off, len, pages, num_pages, checkeof); + ret = striped_read(inode, off, len, pages, num_pages, checkeof, + file->f_flags & O_DIRECT); if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) ret = ceph_copy_page_vector_to_user(pages, data, off, ret); @@ -448,6 +455,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, int flags; int do_sync = 0; int check_caps = 0; + int page_align, io_align; int ret; struct timespec mtime = CURRENT_TIME; @@ -462,6 +470,8 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, else pos = *offset; + io_align = pos & ~PAGE_MASK; + ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); if (ret < 0) return ret; @@ -486,20 +496,26 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, */ more: len = left; + if (file->f_flags & O_DIRECT) + /* write from beginning of first page, regardless of + io alignment */ + page_align = (pos - io_align) & ~PAGE_MASK; + else + page_align = pos & ~PAGE_MASK; req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, ceph_vino(inode), pos, &len, CEPH_OSD_OP_WRITE, flags, ci->i_snap_realm->cached_context, do_sync, ci->i_truncate_seq, ci->i_truncate_size, - &mtime, false, 2); + &mtime, false, 2, page_align); if (!req) return -ENOMEM; num_pages = calc_pages_for(pos, len); if (file->f_flags & O_DIRECT) { - pages = ceph_get_direct_page_vector(data, num_pages, pos, len); + pages = ceph_get_direct_page_vector(data, num_pages); if (IS_ERR(pages)) { ret = PTR_ERR(pages); goto out; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7bc0fbd26af2..8153ee5a8d74 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1752,7 +1752,7 @@ int ceph_do_getattr(struct inode *inode, int mask) return 0; } - dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask)); + dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode); if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1)) return 0; diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 6c91fb032c39..a1af29648fb5 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -79,6 +79,7 @@ struct ceph_osd_request { struct ceph_file_layout r_file_layout; struct ceph_snap_context *r_snapc; /* snap context for writes */ unsigned r_num_pages; /* size of page array (follows) */ + unsigned r_page_alignment; /* io offset in first page */ struct page **r_pages; /* pages for data payload */ int r_pages_from_pool; int r_own_pages; /* if true, i own page list */ @@ -194,7 +195,8 @@ extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *, int do_sync, u32 truncate_seq, u64 truncate_size, struct timespec *mtime, - bool use_mempool, int num_reply); + bool use_mempool, int num_reply, + int page_align); static inline void ceph_osdc_get_request(struct ceph_osd_request *req) { @@ -218,7 +220,8 @@ extern int ceph_osdc_readpages(struct ceph_osd_client *osdc, struct ceph_file_layout *layout, u64 off, u64 *plen, u32 truncate_seq, u64 truncate_size, - struct page **pages, int nr_pages); + struct page **pages, int nr_pages, + int page_align); extern int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 79391994b3ed..6c096239660c 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -71,6 +71,7 @@ void ceph_calc_raw_layout(struct ceph_osd_client *osdc, op->extent.length = objlen; } req->r_num_pages = calc_pages_for(off, *plen); + req->r_page_alignment = off & ~PAGE_MASK; if (op->op == CEPH_OSD_OP_WRITE) op->payload_len = *plen; @@ -419,7 +420,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, u32 truncate_seq, u64 truncate_size, struct timespec *mtime, - bool use_mempool, int num_reply) + bool use_mempool, int num_reply, + int page_align) { struct ceph_osd_req_op ops[3]; struct ceph_osd_request *req; @@ -447,6 +449,10 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, calc_layout(osdc, vino, layout, off, plen, req, ops); req->r_file_layout = *layout; /* keep a copy */ + /* in case it differs from natural alignment that calc_layout + filled in for us */ + req->r_page_alignment = page_align; + ceph_osdc_build_request(req, off, plen, ops, snapc, mtime, @@ -1489,7 +1495,7 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, struct ceph_vino vino, struct ceph_file_layout *layout, u64 off, u64 *plen, u32 truncate_seq, u64 truncate_size, - struct page **pages, int num_pages) + struct page **pages, int num_pages, int page_align) { struct ceph_osd_request *req; int rc = 0; @@ -1499,15 +1505,15 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, req = ceph_osdc_new_request(osdc, layout, vino, off, plen, CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, NULL, 0, truncate_seq, truncate_size, NULL, - false, 1); + false, 1, page_align); if (!req) return -ENOMEM; /* it may be a short read due to an object boundary */ req->r_pages = pages; - dout("readpages final extent is %llu~%llu (%d pages)\n", - off, *plen, req->r_num_pages); + dout("readpages final extent is %llu~%llu (%d pages align %d)\n", + off, *plen, req->r_num_pages, page_align); rc = ceph_osdc_start_request(osdc, req, false); if (!rc) @@ -1533,6 +1539,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, { struct ceph_osd_request *req; int rc = 0; + int page_align = off & ~PAGE_MASK; BUG_ON(vino.snap != CEPH_NOSNAP); req = ceph_osdc_new_request(osdc, layout, vino, off, &len, @@ -1541,7 +1548,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, CEPH_OSD_FLAG_WRITE, snapc, do_sync, truncate_seq, truncate_size, mtime, - nofail, 1); + nofail, 1, page_align); if (!req) return -ENOMEM; @@ -1638,8 +1645,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, m = ceph_msg_get(req->r_reply); if (data_len > 0) { - unsigned data_off = le16_to_cpu(hdr->data_off); - int want = calc_pages_for(data_off & ~PAGE_MASK, data_len); + int want = calc_pages_for(req->r_page_alignment, data_len); if (unlikely(req->r_num_pages < want)) { pr_warning("tid %lld reply %d > expected %d pages\n", -- cgit v1.2.3 From c5c6b19d4b8f5431fca05f28ae9e141045022149 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 9 Nov 2010 12:40:00 -0800 Subject: ceph: explicitly specify page alignment in network messages The alignment used for reading data into or out of pages used to be taken from the data_off field in the message header. This only worked as long as the page alignment matched the object offset, breaking direct io to non-page aligned offsets. Instead, explicitly specify the page alignment next to the page vector in the ceph_msg struct, and use that instead of the message header (which probably shouldn't be trusted). The alloc_msg callback is responsible for filling in this field properly when it sets up the page vector. Signed-off-by: Sage Weil --- include/linux/ceph/messenger.h | 1 + net/ceph/messenger.c | 10 +++++----- net/ceph/osd_client.c | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 5956d62c3057..a108b425fee2 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -82,6 +82,7 @@ struct ceph_msg { struct ceph_buffer *middle; struct page **pages; /* data payload. NOT OWNER. */ unsigned nr_pages; /* size of page array */ + unsigned page_alignment; /* io offset in first page */ struct ceph_pagelist *pagelist; /* instead of pages */ struct list_head list_head; struct kref kref; diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index d379abf873bc..1c7a2ec4f3cc 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -540,8 +540,7 @@ static void prepare_write_message(struct ceph_connection *con) /* initialize page iterator */ con->out_msg_pos.page = 0; if (m->pages) - con->out_msg_pos.page_pos = - le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK; + con->out_msg_pos.page_pos = m->page_alignment; else con->out_msg_pos.page_pos = 0; con->out_msg_pos.data_pos = 0; @@ -1491,7 +1490,7 @@ static int read_partial_message(struct ceph_connection *con) struct ceph_msg *m = con->in_msg; int ret; int to, left; - unsigned front_len, middle_len, data_len, data_off; + unsigned front_len, middle_len, data_len; int datacrc = con->msgr->nocrc; int skip; u64 seq; @@ -1527,7 +1526,6 @@ static int read_partial_message(struct ceph_connection *con) data_len = le32_to_cpu(con->in_hdr.data_len); if (data_len > CEPH_MSG_MAX_DATA_LEN) return -EIO; - data_off = le16_to_cpu(con->in_hdr.data_off); /* verify seq# */ seq = le64_to_cpu(con->in_hdr.seq); @@ -1575,7 +1573,7 @@ static int read_partial_message(struct ceph_connection *con) con->in_msg_pos.page = 0; if (m->pages) - con->in_msg_pos.page_pos = data_off & ~PAGE_MASK; + con->in_msg_pos.page_pos = m->page_alignment; else con->in_msg_pos.page_pos = 0; con->in_msg_pos.data_pos = 0; @@ -2300,6 +2298,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags) /* data */ m->nr_pages = 0; + m->page_alignment = 0; m->pages = NULL; m->pagelist = NULL; m->bio = NULL; @@ -2369,6 +2368,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con, type, front_len); return NULL; } + msg->page_alignment = le16_to_cpu(hdr->data_off); } memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 6c096239660c..3e20a122ffa2 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -391,6 +391,8 @@ void ceph_osdc_build_request(struct ceph_osd_request *req, req->r_request->hdr.data_len = cpu_to_le32(data_len); } + req->r_request->page_alignment = req->r_page_alignment; + BUG_ON(p > msg->front.iov_base + msg->front.iov_len); msg_size = p - msg->front.iov_base; msg->front.iov_len = msg_size; @@ -1657,6 +1659,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, } m->pages = req->r_pages; m->nr_pages = req->r_num_pages; + m->page_alignment = req->r_page_alignment; #ifdef CONFIG_BLOCK m->bio = req->r_bio; #endif -- cgit v1.2.3 From 69669455b049c0f1f04bb306625c5d4db6838b11 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Nov 2010 18:51:34 +0100 Subject: drm/i915: Fix I2C adapter registration Fix many small bugs in I2C adapter registration: * Properly reject unsupported GPIO pin. * Fix improper use of I2C_NAME_SIZE (which is the size of i2c_client.name, not i2c_adapter.name.) * Prefix adapter names with "i915" so that the user knows what the I2C channel is connected to. * Fix swapped characters in the string used to name the GPIO-based adapter. * Add missing comma in gmbus name table. Signed-off-by: Jean Delvare Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_i2c.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 2be4f728ed0c..3dba086e7eea 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -160,7 +160,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) }; struct intel_gpio *gpio; - if (pin < 1 || pin > 7) + if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) return NULL; gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL); @@ -172,7 +172,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) gpio->reg += PCH_GPIOA - GPIOA; gpio->dev_priv = dev_priv; - snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]); + snprintf(gpio->adapter.name, sizeof(gpio->adapter.name), + "i915 GPIO%c", "?BACDE?F"[pin]); gpio->adapter.owner = THIS_MODULE; gpio->adapter.algo_data = &gpio->algo; gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; @@ -349,7 +350,7 @@ int intel_setup_gmbus(struct drm_device *dev) "panel", "dpc", "dpb", - "reserved" + "reserved", "dpd", }; struct drm_i915_private *dev_priv = dev->dev_private; @@ -366,8 +367,8 @@ int intel_setup_gmbus(struct drm_device *dev) bus->adapter.owner = THIS_MODULE; bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, - I2C_NAME_SIZE, - "gmbus %s", + sizeof(bus->adapter.name), + "i915 gmbus %s", names[i]); bus->adapter.dev.parent = &dev->pdev->dev; -- cgit v1.2.3 From c28a9926f28e8c7c52603db58754a78008768ca1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Nov 2010 12:00:11 +0000 Subject: ASoC: Remove broken WM8350 direction constants The WM8350 driver was using some custom constants to interpret the direction of the MCLK signal which had the opposite values to those used as standard by the ASoC core, causing confusion in machine drivers such as the 1133-EV1 board. Reported-by: Tommy Zhu Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/linux/mfd/wm8350/audio.h | 3 --- sound/soc/codecs/wm8350.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h index a95141eafce3..bd581c6fa085 100644 --- a/include/linux/mfd/wm8350/audio.h +++ b/include/linux/mfd/wm8350/audio.h @@ -522,9 +522,6 @@ #define WM8350_MCLK_SEL_PLL_32K 3 #define WM8350_MCLK_SEL_MCLK 5 -#define WM8350_MCLK_DIR_OUT 0 -#define WM8350_MCLK_DIR_IN 1 - /* clock divider id's */ #define WM8350_ADC_CLKDIV 0 #define WM8350_DAC_CLKDIV 1 diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index f4f1fba38eb9..4f3e919a0755 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -831,7 +831,7 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, } /* MCLK direction */ - if (dir == WM8350_MCLK_DIR_OUT) + if (dir == SND_SOC_CLOCK_OUT) wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_MCLK_DIR); else -- cgit v1.2.3 From 0049317edb76d17bfac736b658523c15935391a3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Nov 2010 14:38:58 +0000 Subject: ASoC: Ensure sane WM835x AIF configuration by default Ensure that whatever ran before us leaves the WM835x with a sane default audio interface configuration as we do not override the companding, loopback or tristate settings and do not reset the chip at startup (as it is a PMIC). Reported-by: Keiji Mitsuhisa Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8350.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4f3e919a0755..7611add7f8c3 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1586,6 +1586,13 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, WM8350_OUT2_VU | WM8350_OUT2R_MUTE); + /* Make sure AIF tristating is disabled by default */ + wm8350_clear_bits(wm8350, WM8350_AI_FORMATING, WM8350_AIF_TRI); + + /* Make sure we've got a sane companding setup too */ + wm8350_clear_bits(wm8350, WM8350_ADC_DAC_COMP, + WM8350_DAC_COMP | WM8350_LOOPBACK); + /* Make sure jack detect is disabled to start off with */ wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); -- cgit v1.2.3 From f724bd240adef304e222590826cb0c17d6168b68 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 4 Nov 2010 20:08:12 -0700 Subject: sound/oss/dev_table.c: Use vzalloc Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/oss/dev_table.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c index 727bdb9ba2dc..d8cf3e58dc76 100644 --- a/sound/oss/dev_table.c +++ b/sound/oss/dev_table.c @@ -71,7 +71,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations))); + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations))); sound_nblocks++; if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; @@ -81,7 +81,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, sound_unload_audiodev(num); return -(ENOMEM); } - memset((char *) op, 0, sizeof(struct audio_operations)); init_waitqueue_head(&op->in_sleeper); init_waitqueue_head(&op->out_sleeper); init_waitqueue_head(&op->poll_sleeper); @@ -128,7 +127,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, /* FIXME: This leaks a mixer_operations struct every time its called until you unload sound! */ - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations))); sound_nblocks++; if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; @@ -137,7 +136,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); return -ENOMEM; } - memset((char *) op, 0, sizeof(struct mixer_operations)); memcpy((char *) op, (char *) driver, driver_size); strlcpy(op->name, name, sizeof(op->name)); -- cgit v1.2.3 From ea7dd251251a8d4694e9929104209dcc06220630 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:11:03 +0100 Subject: sound/oss: Remove unnecessary casts of void ptr The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from sound/oss/ Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai --- sound/oss/midibuf.c | 4 ++-- sound/oss/pss.c | 6 +++--- sound/oss/sequencer.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index 782b3b84dac6..ceedb1eff203 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -178,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file) return err; parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; - midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf)); if (midi_in_buf[dev] == NULL) { @@ -188,7 +188,7 @@ int MIDIbuf_open(int dev, struct file *file) } midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf)); if (midi_out_buf[dev] == NULL) { diff --git a/sound/oss/pss.c b/sound/oss/pss.c index e19dd5dcc2de..9b800ce5100e 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -859,7 +859,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, return 0; case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + buf = vmalloc(sizeof(copr_buffer)); if (buf == NULL) return -ENOSPC; if (copy_from_user(buf, arg, sizeof(copr_buffer))) { @@ -871,7 +871,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, return err; case SNDCTL_COPR_SENDMSG: - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + mbuf = vmalloc(sizeof(copr_msg)); if (mbuf == NULL) return -ENOSPC; if (copy_from_user(mbuf, arg, sizeof(copr_msg))) { @@ -895,7 +895,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, case SNDCTL_COPR_RCVMSG: err = 0; - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + mbuf = vmalloc(sizeof(copr_msg)); if (mbuf == NULL) return -ENOSPC; data = (unsigned short *)mbuf->data; diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index e85789e53816..5ea1098ac427 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -1646,13 +1646,13 @@ void sequencer_init(void) { if (sequencer_ok) return; - queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); + queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); return; } - iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ); + iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ); if (iqueue == NULL) { printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); -- cgit v1.2.3 From 89feca1a16b05651d9c500e5572c0d6882873396 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 13 Oct 2010 15:48:24 +0200 Subject: ALSA: HDA: Enable digital mic on IDT 92HD87B BugLink: http://launchpad.net/bugs/673075 According to the datasheet of 92HD87B, there is a digital mic at nid 0x11, so enable it in order to be able to use the mic. Cc: stable@kernel.org Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 93fa59cc60ef..cfd73afad882 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -389,6 +389,11 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { 0x11, 0x20, 0 }; +#define STAC92HD87B_NUM_DMICS 1 +static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = { + 0x11, 0 +}; + #define STAC92HD83XXX_NUM_CAPS 2 static unsigned long stac92hd83xxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), @@ -5452,12 +5457,17 @@ again: stac92hd83xxx_brd_tbl[spec->board_config]); switch (codec->vendor_id) { + case 0x111d76d1: + case 0x111d76d9: + spec->dmic_nids = stac92hd87b_dmic_nids; + spec->num_dmics = stac92xx_connected_ports(codec, + stac92hd87b_dmic_nids, + STAC92HD87B_NUM_DMICS); + /* Fall through */ case 0x111d7666: case 0x111d7667: case 0x111d7668: case 0x111d7669: - case 0x111d76d1: - case 0x111d76d9: spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); spec->pin_nids = stac92hd88xxx_pin_nids; spec->mono_nid = 0; -- cgit v1.2.3 From e9161512017f11050ef2b826cbb10be1673554c6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 9 Nov 2010 18:29:08 +0100 Subject: ALSA: sound/mixart: avoid redefining {readl,write}_{le,be} accessors If the platform already provides a definition for these accessors do not redefine them. The warning was caught on MIPS. Signed-off-by: Florian Fainelli Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_hwdep.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h index a46f5083db99..812e288ef2e7 100644 --- a/sound/pci/mixart/mixart_hwdep.h +++ b/sound/pci/mixart/mixart_hwdep.h @@ -25,11 +25,21 @@ #include +#ifndef readl_be #define readl_be(x) be32_to_cpu(__raw_readl(x)) +#endif + +#ifndef writel_be #define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr) +#endif +#ifndef readl_le #define readl_le(x) le32_to_cpu(__raw_readl(x)) +#endif + +#ifndef writel_le #define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr) +#endif #define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x)) #define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x)) -- cgit v1.2.3 From fa2b30af84e84129b8d4cf955890ad167cc20cf0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 9 Nov 2010 23:00:41 +0100 Subject: ALSA: sound/pci/ctxfi/ctpcm.c: Remove potential for use after free In each function, the value apcm is stored in the private_data field of runtime. At the same time the function ct_atc_pcm_free_substream is stored in the private_free field of the same structure. ct_atc_pcm_free_substream dereferences and ultimately frees the value in the private_data field. But each function can exit in an error case with apcm having been freed, in which case a subsequent call to the private_free function would perform a dereference after free. On the other hand, if the private_free field is not initialized, it is NULL, and not invoked (see snd_pcm_detach_substream in sound/core/pcm.c). To avoid the introduction of a dangling pointer, the initializations of the private_data and private_free fields are moved to the end of the function, past any possible free of apcm. This is safe because the previous calls to snd_pcm_hw_constraint_integer and snd_pcm_hw_constraint_minmax, which take runtime as an argument, do not refer to either of these fields. In each function, there is one error case where apcm needs to be freed, and a call to kfree is added. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e,e1,e2,e3; identifier f,free1,free2; expression a; @@ *e->f = a ... when != e->f = e1 when any if (...) { ... when != free1(...,e,...) when != e->f = e2 * kfree(a) ... when != free2(...,e,...) when != e->f = e3 } // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctpcm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 85ab43e89212..457d21189b0d 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -129,8 +129,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream) apcm->substream = substream; apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; if (IEC958 == substream->pcm->device) { runtime->hw = ct_spdif_passthru_playback_hw; atc->spdif_out_passthru(atc, 1); @@ -155,8 +153,12 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream) } apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) + if (!apcm->timer) { + kfree(apcm); return -ENOMEM; + } + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; return 0; } @@ -278,8 +280,6 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream) apcm->started = 0; apcm->substream = substream; apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; runtime->hw = ct_pcm_capture_hw; runtime->hw.rate_max = atc->rsr * atc->msr; @@ -298,8 +298,12 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream) } apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) + if (!apcm->timer) { + kfree(apcm); return -ENOMEM; + } + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; return 0; } -- cgit v1.2.3 From e2e9566230e0c93d89948cbc799a191d35383d09 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 10 Nov 2010 15:55:05 +0100 Subject: ALSA: AT73C213: Rectify misleading comment. The Atmel SSC can divide by even numbers, not only powers of two. Signed-off-by: Peter Rosin Signed-off-by: Takashi Iwai --- sound/spi/at73c213.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 1bc56b2b94e2..337a00241a1f 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -155,7 +155,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) if (max_tries < 1) max_tries = 1; - /* ssc_div must be a power of 2. */ + /* ssc_div must be even. */ ssc_div = (ssc_div + 1) & ~1UL; if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { -- cgit v1.2.3 From bbde7814cbc54d6b564d3f65b4b0e82eddef30a6 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Thu, 11 Nov 2010 09:02:30 +1300 Subject: Fix Atmel soc audio boards Kconfig dependency Add Kconfig dependency on AT91_PROGRAMMABLE_CLOCKS for the Atmel SoC audio SAM9G20-EK and PlayPaq boards. Fixes link errors on missing clk_set_parent and clk_set_rate when building without AT91_PROGRAMMABLE_CLOCKS. Signed-off-by: Ryan Mallon Acked-by: Geoffrey Wossum Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e720d5e6f04c..bee3c94f58b0 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -16,7 +16,8 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC + depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \ + AT91_PROGRAMMABLE_CLOCKS select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 help @@ -25,7 +26,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT32_SOC_PLAYPAQ tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_ATMEL_SOC && BOARD_PLAYPAQ + depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS select SND_ATMEL_SOC_SSC select SND_SOC_WM8510 help -- cgit v1.2.3 From 241b652f1995de138106afd2f2e4eda9f8a3c240 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 5 Nov 2010 09:59:01 -0400 Subject: xhci: Remove excessive printks with shared IRQs. If the xHCI host controller shares an interrupt line with another device, the xHCI driver needs to check if the interrupt was generated by its hardware. Unfortunately, the user will see a ton of "Spurious interrupt." lines if the other hardware interrupts often. Lawrence found his dmesg output cluttered with this output when the xHCI host shared an interrupt with his i915 hardware. Remove the warning, as sharing an interrupt is a normal thing. This should be applied to the 2.6.36 stable tree. Signed-off-by: Sarah Sharp Reported-by: Lawrence Rust Cc: stable@kernel.org --- drivers/usb/host/xhci-ring.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9f3115e729b1..df558f6f84e3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2104,7 +2104,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) if (!(status & STS_EINT)) { spin_unlock(&xhci->lock); - xhci_warn(xhci, "Spurious interrupt.\n"); return IRQ_NONE; } xhci_dbg(xhci, "op reg status = %08x\n", status); -- cgit v1.2.3 From 74bb844af8ec6a4c360b1fc7feb139801c0cacfd Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Wed, 27 Oct 2010 16:44:52 +0800 Subject: xHCI: release spinlock when setup interrupt Jiri Slaby reports spinlock is held while calling kmalloc(GFP_KERNEL) and request_irq() in xhci_resume(). Release the spinlock when setup interrupt. Reported-by: Jiri Slaby Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5d7d4e951ea4..7c8d70fbe113 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -714,6 +714,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; } + spin_unlock_irq(&xhci->lock); /* Re-setup MSI-X */ if (hcd->irq) free_irq(hcd->irq, hcd); @@ -736,6 +737,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) hcd->irq = pdev->irq; } + spin_lock_irq(&xhci->lock); /* step 4: set Run/Stop bit */ command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_RUN; -- cgit v1.2.3 From dc07c91b9b4067022210e68d914a6890a4d70622 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 11 Nov 2010 17:43:57 +0800 Subject: xHCI: fix wMaxPacketSize mask USB2.0 spec 9.6.6 says: For all endpoints, bit 10..0 specify the maximum packet size(in bytes). So the wMaxPacketSize mask should be 0x7ff rather than 0x3ff. This patch should be queued for the stable tree. The bug in xhci_endpoint_init() was present as far back as 2.6.31, and the bug in xhci_get_max_esit_payload() was present when the function was introduced in 2.6.34. Reported-by: Sander Eikelenboom Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/host/xhci-mem.c | 4 ++-- drivers/usb/host/xhci.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 202770676da3..d178761c3981 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1045,7 +1045,7 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, if (udev->speed == USB_SPEED_SUPER) return ep->ss_ep_comp.wBytesPerInterval; - max_packet = ep->desc.wMaxPacketSize & 0x3ff; + max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize); max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; /* A 0 in max burst means 1 transfer per ESIT */ return max_packet * (max_burst + 1); @@ -1135,7 +1135,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Fall through */ case USB_SPEED_FULL: case USB_SPEED_LOW: - max_packet = ep->desc.wMaxPacketSize & 0x3ff; + max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize); ep_ctx->ep_info2 |= MAX_PACKET(max_packet); break; default: diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 93d3bf4d213c..85e65647d445 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -621,6 +621,11 @@ struct xhci_ep_ctx { #define MAX_PACKET_MASK (0xffff << 16) #define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff) +/* Get max packet size from ep desc. Bit 10..0 specify the max packet size. + * USB2.0 spec 9.6.6. + */ +#define GET_MAX_PACKET(p) ((p) & 0x7ff) + /* tx_info bitmasks */ #define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) #define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) -- cgit v1.2.3 From e060e7af98182494b764d002eba7fa022fe91bdf Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 11 Nov 2010 12:37:43 -0800 Subject: xen: set vma flag VM_PFNMAP in the privcmd mmap file_op Set VM_PFNMAP in the privcmd mmap file_op, rather than later in xen_remap_domain_mfn_range when it is too late because vma_wants_writenotify has already been called and vm_page_prot has already been modified. Signed-off-by: Stefano Stabellini Signed-off-by: Jeremy Fitzhardinge --- arch/x86/xen/mmu.c | 3 ++- drivers/xen/xenfs/privcmd.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index f08ea045620f..792de4349c79 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2299,7 +2299,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP); - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; + BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) == + (VM_PFNMAP | VM_RESERVED | VM_IO))); rmd.mfn = mfn; rmd.prot = prot; diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c index 2eb04c842511..88474d460d82 100644 --- a/drivers/xen/xenfs/privcmd.c +++ b/drivers/xen/xenfs/privcmd.c @@ -380,8 +380,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) if (xen_feature(XENFEAT_auto_translated_physmap)) return -ENOSYS; - /* DONTCOPY is essential for Xen as copy_page_range is broken. */ - vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; + /* DONTCOPY is essential for Xen because copy_page_range doesn't know + * how to recreate these mappings */ + vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; vma->vm_ops = &privcmd_vm_ops; vma->vm_private_data = NULL; -- cgit v1.2.3 From a1629c3b24f26ec1b0f534874af674a6b4c1540b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 11 Nov 2010 15:24:06 -0800 Subject: ceph: fix dangling pointer Clear fi->last_name when it's freed. The only caller is rewinddir() (or equivalent lseek). Signed-off-by: Sage Weil --- fs/ceph/dir.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index e0a2dc6fcafc..1e11ed716f85 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -414,6 +414,7 @@ static void reset_readdir(struct ceph_file_info *fi) fi->last_readdir = NULL; } kfree(fi->last_name); + fi->last_name = NULL; fi->next_offset = 2; /* compensate for . and .. */ if (fi->dentry) { dput(fi->dentry); -- cgit v1.2.3 From 7b88dadc13e0004947de52df128dbd5b0754ed0a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 11 Nov 2010 16:48:59 -0800 Subject: ceph: fix frag offset for non-leftmost frags We start at offset 2 for the leftmost frag, and 0 for subsequent frags. When we reach the end (rightmost), we go back to 2. This fixes readdir on fragmented (large) directories. Signed-off-by: Sage Weil --- fs/ceph/dir.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 1e11ed716f85..5f67728ba4d7 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -336,7 +336,10 @@ more: if (req->r_reply_info.dir_end) { kfree(fi->last_name); fi->last_name = NULL; - fi->next_offset = 2; + if (ceph_frag_is_rightmost(frag)) + fi->next_offset = 2; + else + fi->next_offset = 0; } else { rinfo = &req->r_reply_info; err = note_last_dentry(fi, -- cgit v1.2.3 From 7e77506a5918d82cafa2ffa783ab57c23f9e9817 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Sep 2010 12:37:26 +0100 Subject: xen: implement XENMEM_machphys_mapping This hypercall allows Xen to specify a non-default location for the machine to physical mapping. This capability is used when running a 32 bit domain 0 on a 64 bit hypervisor to shrink the hypervisor hole to exactly the size required. [ Impact: add Xen hypercall definitions ] Signed-off-by: Ian Campbell Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Stefano Stabellini --- arch/x86/include/asm/xen/interface.h | 6 +++--- arch/x86/include/asm/xen/interface_32.h | 5 +++++ arch/x86/include/asm/xen/interface_64.h | 13 +------------ arch/x86/include/asm/xen/page.h | 7 ++++--- arch/x86/xen/enlighten.c | 7 +++++++ arch/x86/xen/mmu.c | 14 ++++++++++++++ include/xen/interface/memory.h | 13 +++++++++++++ 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h index e8506c1f0c55..1c10c88ee4e1 100644 --- a/arch/x86/include/asm/xen/interface.h +++ b/arch/x86/include/asm/xen/interface.h @@ -61,9 +61,9 @@ DEFINE_GUEST_HANDLE(void); #define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) #endif -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT) /* Maximum number of virtual CPUs in multi-processor guests. */ #define MAX_VIRT_CPUS 32 diff --git a/arch/x86/include/asm/xen/interface_32.h b/arch/x86/include/asm/xen/interface_32.h index 42a7e004ae5c..8413688b2571 100644 --- a/arch/x86/include/asm/xen/interface_32.h +++ b/arch/x86/include/asm/xen/interface_32.h @@ -32,6 +32,11 @@ /* And the trap vector is... */ #define TRAP_INSTR "int $0x82" +#define __MACH2PHYS_VIRT_START 0xF5800000 +#define __MACH2PHYS_VIRT_END 0xF6800000 + +#define __MACH2PHYS_SHIFT 2 + /* * Virtual addresses beyond this are not modifiable by guest OSes. The * machine->physical mapping table starts at this address, read-only. diff --git a/arch/x86/include/asm/xen/interface_64.h b/arch/x86/include/asm/xen/interface_64.h index 100d2662b97c..839a4811cf98 100644 --- a/arch/x86/include/asm/xen/interface_64.h +++ b/arch/x86/include/asm/xen/interface_64.h @@ -39,18 +39,7 @@ #define __HYPERVISOR_VIRT_END 0xFFFF880000000000 #define __MACH2PHYS_VIRT_START 0xFFFF800000000000 #define __MACH2PHYS_VIRT_END 0xFFFF804000000000 - -#ifndef HYPERVISOR_VIRT_START -#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) -#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) -#endif - -#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) -#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) -#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif +#define __MACH2PHYS_SHIFT 3 /* * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index dd8c1414b3d5..8760cc60a21c 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,8 @@ typedef struct xpaddr { #define MAX_DOMAIN_PAGES \ ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE)) +extern unsigned long *machine_to_phys_mapping; +extern unsigned int machine_to_phys_order; extern unsigned long get_phys_to_machine(unsigned long pfn); extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); @@ -69,10 +72,8 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) if (xen_feature(XENFEAT_auto_translated_physmap)) return mfn; -#if 0 if (unlikely((mfn >> machine_to_phys_order) != 0)) - return max_mapnr; -#endif + return ~0; pfn = 0; /* diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 235c0f4d3861..bd3554934613 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -75,6 +75,11 @@ DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); enum xen_domain_type xen_domain_type = XEN_NATIVE; EXPORT_SYMBOL_GPL(xen_domain_type); +unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; +EXPORT_SYMBOL(machine_to_phys_mapping); +unsigned int machine_to_phys_order; +EXPORT_SYMBOL(machine_to_phys_order); + struct start_info *xen_start_info; EXPORT_SYMBOL_GPL(xen_start_info); @@ -1097,6 +1102,8 @@ asmlinkage void __init xen_start_kernel(void) xen_domain_type = XEN_PV_DOMAIN; + xen_setup_machphys_mapping(); + /* Install Xen paravirt ops */ pv_info = xen_info; pv_init_ops = xen_init_ops; diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 21ed8d7f75a5..bd2713a82571 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2034,6 +2034,20 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) set_page_prot(pmd, PAGE_KERNEL_RO); } +void __init xen_setup_machphys_mapping(void) +{ + struct xen_machphys_mapping mapping; + unsigned long machine_to_phys_nr_ents; + + if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { + machine_to_phys_mapping = (unsigned long *)mapping.v_start; + machine_to_phys_nr_ents = mapping.max_mfn + 1; + } else { + machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; + } + machine_to_phys_order = fls(machine_to_phys_nr_ents - 1); +} + #ifdef CONFIG_X86_64 static void convert_pfn_mfn(void *v) { diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h index d7a6c13bde69..eac3ce153719 100644 --- a/include/xen/interface/memory.h +++ b/include/xen/interface/memory.h @@ -140,6 +140,19 @@ struct xen_machphys_mfn_list { }; DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); +/* + * Returns the location in virtual address space of the machine_to_phys + * mapping table. Architectures which do not have a m2p table, or which do not + * map it by default into guest address space, do not implement this command. + * arg == addr of xen_machphys_mapping_t. + */ +#define XENMEM_machphys_mapping 12 +struct xen_machphys_mapping { + unsigned long v_start, v_end; /* Start and end virtual addresses. */ + unsigned long max_mfn; /* Maximum MFN that can be looked up. */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); + /* * Sets the GPFN at which a particular page appears in the specified guest's * pseudophysical address space. -- cgit v1.2.3 From 85345517fe6d4de27b0d6ca19fef9d28ac947c4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 13 Nov 2010 09:49:11 +0000 Subject: drm/i915: Retire any pending operations on the old scanout when switching An old and oft reported bug, is that of the GPU hanging on a MI_WAIT_FOR_EVENT following a mode switch. The cause is that the GPU is waiting on a scanline counter on an inactive pipe, and so waits for a very long time until eventually the user reboots his machine. We can prevent this either by moving the WAIT into the kernel and thereby incurring considerable cost on every swapbuffers, or by waiting for the GPU to retire the last batch that accesses the framebuffer before installing a new one. As mode switches are much rarer than swap buffers, this looks like an easy choice. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=28964 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29252 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 14 ++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 90414ae86afc..409826da3099 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1045,6 +1045,8 @@ void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain); +int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, + bool interruptible); int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eba9b1615228..951e3d463113 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2907,6 +2907,20 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, return 0; } +int +i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, + bool interruptible) +{ + if (!obj->active) + return 0; + + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(obj->base.dev, NULL, obj->ring, + 0, obj->base.write_domain); + + return i915_gem_object_wait_rendering(&obj->base, interruptible); +} + /** * Moves a single object to the CPU read, and possibly write domain. * diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 48d8fd686ea9..bee24b1a58e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1611,6 +1611,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, wait_event(dev_priv->pending_flip_queue, atomic_read(&obj_priv->pending_flip) == 0); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. + */ + ret = i915_gem_object_flush_gpu(obj_priv, false); + if (ret) { + i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } } ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, -- cgit v1.2.3 From fba4312e223f1187efc8c083daed70e57fa9c9d3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 14 Nov 2010 20:24:35 -0500 Subject: drm/radeon/kms: fix and unify tiled buffer alignment checking for r6xx/7xx Tiled buffers have the same alignment requirements regardless of whether the surface is for db, cb, or textures. Previously, the calculations where inconsistent for each buffer type. - Unify the alignment calculations in a common function - Standardize the alignment units (pixels for pitch/height/depth, bytes for base) - properly check the buffer base alignments Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 309 ++++++++++++++++++++++++--------------- drivers/gpu/drm/radeon/r600d.h | 6 + 2 files changed, 199 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 37cc2aa9f923..0f90fc3482ce 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -50,6 +50,7 @@ struct r600_cs_track { u32 nsamples; u32 cb_color_base_last[8]; struct radeon_bo *cb_color_bo[8]; + u64 cb_color_bo_mc[8]; u32 cb_color_bo_offset[8]; struct radeon_bo *cb_color_frag_bo[8]; struct radeon_bo *cb_color_tile_bo[8]; @@ -67,6 +68,7 @@ struct r600_cs_track { u32 db_depth_size; u32 db_offset; struct radeon_bo *db_bo; + u64 db_bo_mc; }; static inline int r600_bpe_from_format(u32 *bpe, u32 format) @@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format) return 0; } +struct array_mode_checker { + int array_mode; + u32 group_size; + u32 nbanks; + u32 npipes; + u32 nsamples; + u32 bpe; +}; + +/* returns alignment in pixels for pitch/height/depth and bytes for base */ +static inline int r600_get_array_mode_alignment(struct array_mode_checker *values, + u32 *pitch_align, + u32 *height_align, + u32 *depth_align, + u64 *base_align) +{ + u32 tile_width = 8; + u32 tile_height = 8; + u32 macro_tile_width = values->nbanks; + u32 macro_tile_height = values->npipes; + u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples; + u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes; + + switch (values->array_mode) { + case ARRAY_LINEAR_GENERAL: + /* technically tile_width/_height for pitch/height */ + *pitch_align = 1; /* tile_width */ + *height_align = 1; /* tile_height */ + *depth_align = 1; + *base_align = 1; + break; + case ARRAY_LINEAR_ALIGNED: + *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe)); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_1D_TILED_THIN1: + *pitch_align = max((u32)tile_width, + (u32)(values->group_size / + (tile_height * values->bpe * values->nsamples))); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_2D_TILED_THIN1: + *pitch_align = max((u32)macro_tile_width, + (u32)(((values->group_size / tile_height) / + (values->bpe * values->nsamples)) * + values->nbanks)) * tile_width; + *height_align = macro_tile_height * tile_height; + *depth_align = 1; + *base_align = max(macro_tile_bytes, + (*pitch_align) * values->bpe * (*height_align) * values->nsamples); + break; + default: + return -EINVAL; + } + + return 0; +} + static void r600_cs_track_init(struct r600_cs_track *track) { int i; @@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track) track->cb_color_info[i] = 0; track->cb_color_bo[i] = NULL; track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_bo_mc[i] = 0xFFFFFFFF; } track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->db_bo = NULL; + track->db_bo_mc = 0xFFFFFFFF; /* assume the biggest format and that htile is enabled */ track->db_depth_info = 7 | (1 << 25); track->db_depth_view = 0xFFFFC000; @@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track) static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) { struct r600_cs_track *track = p->track; - u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align; + u32 bpe = 0, slice_tile_max, size, tmp; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; volatile u32 *ib = p->ib->ptr; unsigned array_mode; @@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) i, track->cb_color_info[i]); return -EINVAL; } - /* pitch is the number of 8x8 tiles per row */ - pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1; + /* pitch in pixels */ + pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8; slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]); + + base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i]; + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, + G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, + track->cb_color_info[i]); + return -EINVAL; + } switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: - /* technically height & 0x7 */ break; case V_0280A0_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* avoid breaking userspace */ if (height > 7) height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, @@ -244,8 +293,24 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) track->cb_color_info[i]); return -EINVAL; } + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + /* check offset */ - tmp = height * pitch * 8 * bpe; + tmp = height * pitch * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ @@ -260,15 +325,11 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) return -EINVAL; } } - if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]); - return -EINVAL; - } /* limit max tile */ - tmp = (height * pitch * 8) >> 6; + tmp = (height * pitch) >> 6; if (tmp < slice_tile_max) slice_tile_max = tmp; - tmp = S_028060_PITCH_TILE_MAX(pitch - 1) | + tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) | S_028060_SLICE_TILE_MAX(slice_tile_max - 1); ib[track->cb_color_size_idx[i]] = tmp; return 0; @@ -310,7 +371,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) /* Check depth buffer */ if (G_028800_STENCIL_ENABLE(track->db_depth_control) || G_028800_Z_ENABLE(track->db_depth_control)) { - u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max; + u32 nviews, bpe, ntiles, size, slice_tile_max; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; + int array_mode; + if (track->db_bo == NULL) { dev_warn(p->dev, "z/stencil with no depth buffer\n"); return -EINVAL; @@ -353,41 +419,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); } else { size = radeon_bo_size(track->db_bo); - pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1; + /* pitch in pixels */ + pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8; slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; - switch (G_028010_ARRAY_MODE(track->db_depth_info)) { + base_offset = track->db_bo_mc + track->db_offset; + array_mode = G_028010_ARRAY_MODE(track->db_depth_info); + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_028010_ARRAY_MODE(track->db_depth_info), + track->db_depth_info); + return -EINVAL; + } + switch (array_mode) { case V_028010_ARRAY_1D_TILED_THIN1: - pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8); - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* don't break userspace */ height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_028010_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, @@ -395,15 +454,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) track->db_depth_info); return -EINVAL; } - if (!IS_ALIGNED(track->db_offset, track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset); + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { - dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n", + dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n", track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, radeon_bo_size(track->db_bo)); return -EINVAL; @@ -954,6 +1025,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->cb_color_base_last[tmp] = ib[idx]; track->cb_color_bo[tmp] = reloc->robj; + track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset; break; case DB_DEPTH_BASE: r = r600_cs_packet_next_reloc(p, &reloc); @@ -965,6 +1037,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx track->db_offset = radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->db_bo = reloc->robj; + track->db_bo_mc = reloc->lobj.gpu_offset; break; case DB_HTILE_DATA_BASE: case SQ_PGM_START_FS: @@ -1086,16 +1159,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, struct radeon_bo *texture, struct radeon_bo *mipmap, + u64 base_offset, + u64 mip_offset, u32 tiling_flags) { struct r600_cs_track *track = p->track; u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0; - u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align; + u32 word0, word1, l0_size, mipmap_size; + u32 height_align, pitch, pitch_align, depth_align; + u64 base_align; + struct array_mode_checker array_check; /* on legacy kernel we don't perform advanced check */ if (p->rdev == NULL) return 0; + /* convert to bytes */ + base_offset <<= 8; + mip_offset <<= 8; + word0 = radeon_get_ib_value(p, idx + 0); if (tiling_flags & RADEON_TILING_MACRO) word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); @@ -1128,46 +1210,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i return -EINVAL; } - pitch = G_038000_PITCH(word0) + 1; - switch (G_038000_TILE_MODE(word0)) { - case V_038000_ARRAY_LINEAR_GENERAL: - pitch_align = 1; - /* XXX check height align */ - break; - case V_038000_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - default: - dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, - G_038000_TILE_MODE(word0), word0); + /* pitch in texels */ + pitch = (G_038000_PITCH(word0) + 1) * 8; + array_check.array_mode = G_038000_TILE_MODE(word0); + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = 1; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", + __func__, __LINE__, G_038000_TILE_MODE(word0)); + return -EINVAL; + } + + /* XXX check height as well... */ + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n", + __func__, __LINE__, base_offset); + return -EINVAL; + } + if (!IS_ALIGNED(mip_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n", + __func__, __LINE__, mip_offset); return -EINVAL; } - /* XXX check offset align */ word0 = radeon_get_ib_value(p, idx + 4); word1 = radeon_get_ib_value(p, idx + 5); @@ -1402,7 +1476,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p, mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); mipmap = reloc->robj; r = r600_check_texture_resource(p, idx+(i*7)+1, - texture, mipmap, reloc->lobj.tiling_flags); + texture, mipmap, + base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2), + mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3), + reloc->lobj.tiling_flags); if (r) return r; ib[idx+1+(i*7)+2] += base_offset; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 966a793e225b..bff4dc4f410f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -51,6 +51,12 @@ #define PTE_READABLE (1 << 5) #define PTE_WRITEABLE (1 << 6) +/* tiling bits */ +#define ARRAY_LINEAR_GENERAL 0x00000000 +#define ARRAY_LINEAR_ALIGNED 0x00000001 +#define ARRAY_1D_TILED_THIN1 0x00000002 +#define ARRAY_2D_TILED_THIN1 0x00000004 + /* Registers */ #define ARB_POP 0x2418 #define ENABLE_TC128 (1 << 30) -- cgit v1.2.3 From a41c73e04673b47730df682446f0d52f95e32a5b Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 14 Nov 2010 23:08:27 +0300 Subject: drm: radeon: fix error value sign enable_vblank implementations should use negative result to indicate error. radeon_enable_vblank() returns EINVAL in this case. Change this to -EINVAL. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 2f349a300195..465746bd51b7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } else { switch (crtc) { @@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } -- cgit v1.2.3 From fcb7193096969ca9e5b9219b9a99ddf299d4054f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 15 Nov 2010 00:23:42 -0800 Subject: Input: sysrq - pass along lone Alt + SysRq When user presses and releases Alt + SysRq without pressing any of the hot keys re-inject the combination and pass it on to userspace instead of suppressing it - maybe he or she wanted to take print screen instead of invoking SysRq handler. Also pass along release events for keys that have been pressed before SysRq mode has been invoked so that keys do not appear to be "stuck". Acked-by: Jason Wessel Tested-by: Jason Wessel Signed-off-by: Dmitry Torokhov --- drivers/char/sysrq.c | 169 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 45 deletions(-) diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index eaa5d3efa79d..c556ed9db13d 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -554,7 +554,7 @@ EXPORT_SYMBOL(handle_sysrq); #ifdef CONFIG_INPUT /* Simple translation table for the SysRq keys */ -static const unsigned char sysrq_xlate[KEY_MAX + 1] = +static const unsigned char sysrq_xlate[KEY_CNT] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -563,53 +563,129 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] = "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ "\r\000/"; /* 0x60 - 0x6f */ -static bool sysrq_down; -static int sysrq_alt_use; -static int sysrq_alt; -static DEFINE_SPINLOCK(sysrq_event_lock); +struct sysrq_state { + struct input_handle handle; + struct work_struct reinject_work; + unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned int alt; + unsigned int alt_use; + bool active; + bool need_reinject; +}; + +static void sysrq_reinject_alt_sysrq(struct work_struct *work) +{ + struct sysrq_state *sysrq = + container_of(work, struct sysrq_state, reinject_work); + struct input_handle *handle = &sysrq->handle; + unsigned int alt_code = sysrq->alt_use; + + if (sysrq->need_reinject) { + /* Simulate press and release of Alt + SysRq */ + input_inject_event(handle, EV_KEY, alt_code, 1); + input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1); + input_inject_event(handle, EV_SYN, SYN_REPORT, 1); + + input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0); + input_inject_event(handle, EV_KEY, alt_code, 0); + input_inject_event(handle, EV_SYN, SYN_REPORT, 1); + } +} -static bool sysrq_filter(struct input_handle *handle, unsigned int type, - unsigned int code, int value) +static bool sysrq_filter(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { + struct sysrq_state *sysrq = handle->private; + bool was_active = sysrq->active; bool suppress; - /* We are called with interrupts disabled, just take the lock */ - spin_lock(&sysrq_event_lock); + switch (type) { - if (type != EV_KEY) - goto out; + case EV_SYN: + suppress = false; + break; - switch (code) { + case EV_KEY: + switch (code) { - case KEY_LEFTALT: - case KEY_RIGHTALT: - if (value) - sysrq_alt = code; - else { - if (sysrq_down && code == sysrq_alt_use) - sysrq_down = false; + case KEY_LEFTALT: + case KEY_RIGHTALT: + if (!value) { + /* One of ALTs is being released */ + if (sysrq->active && code == sysrq->alt_use) + sysrq->active = false; - sysrq_alt = 0; + sysrq->alt = KEY_RESERVED; + + } else if (value != 2) { + sysrq->alt = code; + sysrq->need_reinject = false; + } + break; + + case KEY_SYSRQ: + if (value == 1 && sysrq->alt != KEY_RESERVED) { + sysrq->active = true; + sysrq->alt_use = sysrq->alt; + /* + * If nothing else will be pressed we'll need + * to * re-inject Alt-SysRq keysroke. + */ + sysrq->need_reinject = true; + } + + /* + * Pretend that sysrq was never pressed at all. This + * is needed to properly handle KGDB which will try + * to release all keys after exiting debugger. If we + * do not clear key bit it KGDB will end up sending + * release events for Alt and SysRq, potentially + * triggering print screen function. + */ + if (sysrq->active) + clear_bit(KEY_SYSRQ, handle->dev->key); + + break; + + default: + if (sysrq->active && value && value != 2) { + sysrq->need_reinject = false; + __handle_sysrq(sysrq_xlate[code], true); + } + break; } - break; - case KEY_SYSRQ: - if (value == 1 && sysrq_alt) { - sysrq_down = true; - sysrq_alt_use = sysrq_alt; + suppress = sysrq->active; + + if (!sysrq->active) { + /* + * If we are not suppressing key presses keep track of + * keyboard state so we can release keys that have been + * pressed before entering SysRq mode. + */ + if (value) + set_bit(code, sysrq->key_down); + else + clear_bit(code, sysrq->key_down); + + if (was_active) + schedule_work(&sysrq->reinject_work); + + } else if (value == 0 && + test_and_clear_bit(code, sysrq->key_down)) { + /* + * Pass on release events for keys that was pressed before + * entering SysRq mode. + */ + suppress = false; } break; default: - if (sysrq_down && value && value != 2) - __handle_sysrq(sysrq_xlate[code], true); + suppress = sysrq->active; break; } -out: - suppress = sysrq_down; - spin_unlock(&sysrq_event_lock); - return suppress; } @@ -617,28 +693,28 @@ static int sysrq_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { - struct input_handle *handle; + struct sysrq_state *sysrq; int error; - sysrq_down = false; - sysrq_alt = 0; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) + sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL); + if (!sysrq) return -ENOMEM; - handle->dev = dev; - handle->handler = handler; - handle->name = "sysrq"; + INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq); + + sysrq->handle.dev = dev; + sysrq->handle.handler = handler; + sysrq->handle.name = "sysrq"; + sysrq->handle.private = sysrq; - error = input_register_handle(handle); + error = input_register_handle(&sysrq->handle); if (error) { pr_err("Failed to register input sysrq handler, error %d\n", error); goto err_free; } - error = input_open_device(handle); + error = input_open_device(&sysrq->handle); if (error) { pr_err("Failed to open input device, error %d\n", error); goto err_unregister; @@ -647,17 +723,20 @@ static int sysrq_connect(struct input_handler *handler, return 0; err_unregister: - input_unregister_handle(handle); + input_unregister_handle(&sysrq->handle); err_free: - kfree(handle); + kfree(sysrq); return error; } static void sysrq_disconnect(struct input_handle *handle) { + struct sysrq_state *sysrq = handle->private; + input_close_device(handle); + cancel_work_sync(&sysrq->reinject_work); input_unregister_handle(handle); - kfree(handle); + kfree(sysrq); } /* -- cgit v1.2.3 From ccb3b84fa0fb6fb7b46b461881fd60440f579696 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sat, 13 Nov 2010 14:53:41 +0200 Subject: ASoC: RX1950: Fix hw_params function Unfortunatelly, I misunderstood datasheet, and on s3c244x-iis when MPLLin source for master clock is selected, prescaler has no effect. Remove dividor calculation for 44100 rate; remove 88200 rate at all, rx1950 can't do it. Signed-off-by: Vasily Khoruzhick Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/rx1950_uda1380.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c index ffd5cf2fb0a9..468cc11fdf47 100644 --- a/sound/soc/s3c24xx/rx1950_uda1380.c +++ b/sound/soc/s3c24xx/rx1950_uda1380.c @@ -50,7 +50,6 @@ static unsigned int rates[] = { 16000, 44100, 48000, - 88200, }; static struct snd_pcm_hw_constraint_list hw_rates = { @@ -130,7 +129,6 @@ static const struct snd_soc_dapm_route audio_map[] = { }; static struct platform_device *s3c24xx_snd_device; -static struct clk *xtal; static int rx1950_startup(struct snd_pcm_substream *substream) { @@ -179,10 +177,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, case 44100: case 88200: clk_source = S3C24XX_CLKSRC_MPLL; - fs_mode = S3C2410_IISMOD_256FS; - div = clk_get_rate(xtal) / (256 * rate); - if (clk_get_rate(xtal) % (256 * rate) > (128 * rate)) - div++; + fs_mode = S3C2410_IISMOD_384FS; + div = 1; break; default: printk(KERN_ERR "%s: rate %d is not supported\n", @@ -210,7 +206,7 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, /* set MCLK division for sample rate */ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, - S3C2410_IISMOD_384FS); + fs_mode); if (ret < 0) return ret; @@ -295,17 +291,8 @@ static int __init rx1950_init(void) goto err_plat_add; } - xtal = clk_get(&s3c24xx_snd_device->dev, "xtal"); - - if (IS_ERR(xtal)) { - ret = PTR_ERR(xtal); - platform_device_unregister(s3c24xx_snd_device); - goto err_clk; - } - return 0; -err_clk: err_plat_add: err_plat_alloc: err_gpio_conf: @@ -320,7 +307,6 @@ static void __exit rx1950_exit(void) platform_device_unregister(s3c24xx_snd_device); snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); - clk_put(xtal); gpio_free(S3C2410_GPA(1)); } -- cgit v1.2.3 From bcbb243396b82b0369465e9a547b7d5278cd26ad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Nov 2010 15:14:55 +0000 Subject: ASoC: Fix dapm_seq_compare() for multi-component Ensure that we keep all widget powerups in DAPM sequence by making the CODEC the last thing we compare on rather than the first thing. Also fix the fact that we're currently comparing the widget pointers rather than the CODEC pointers when we do the substraction so we won't get stable results. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7d85c6496afa..75ed6491222d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -683,12 +683,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, struct snd_soc_dapm_widget *b, int sort[]) { - if (a->codec != b->codec) - return (unsigned long)a - (unsigned long)b; if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->reg != b->reg) return a->reg - b->reg; + if (a->codec != b->codec) + return (unsigned long)a->codec - (unsigned long)b->codec; return 0; } -- cgit v1.2.3 From 3b42a96dc7870c53d20b419185737d3b8f7a7b74 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Mon, 15 Nov 2010 06:01:59 +0000 Subject: net: rtnetlink.h -- only include linux/netdevice.h when used by the kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit below added a new helper dev_ingress_queue to cleanly obtain the ingress queue pointer. This necessitated including 'linux/netdevice.h': commit 24824a09e35402b8d58dcc5be803a5ad3937bdba Author: Eric Dumazet Date: Sat Oct 2 06:11:55 2010 +0000 net: dynamic ingress_queue allocation However this include triggers issues for applications in userspace which use the rtnetlink interfaces. Commonly this requires they include 'net/if.h' and 'linux/rtnetlink.h' leading to a compiler error as below: In file included from /usr/include/linux/netdevice.h:28:0, from /usr/include/linux/rtnetlink.h:9, from t.c:2: /usr/include/linux/if.h:135:8: error: redefinition of ‘struct ifmap’ /usr/include/net/if.h:112:8: note: originally defined here /usr/include/linux/if.h:169:8: error: redefinition of ‘struct ifreq’ /usr/include/net/if.h:127:8: note: originally defined here /usr/include/linux/if.h:218:8: error: redefinition of ‘struct ifconf’ /usr/include/net/if.h:177:8: note: originally defined here The new helper is only defined for the kernel and protected by __KERNEL__ therefore we can simply pull the include down into the same protected section. Signed-off-by: Andy Whitcroft Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index d42f274418b8..bbad657a3725 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -6,7 +6,6 @@ #include #include #include -#include /* rtnetlink families. Values up to 127 are reserved for real address * families, values above 128 may be used arbitrarily. @@ -606,6 +605,7 @@ struct tcamsg { #ifdef __KERNEL__ #include +#include static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str) { -- cgit v1.2.3 From 62370e2b9376ea7b76e0423de28ccb322c17e2da Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Thu, 11 Nov 2010 11:44:32 -0600 Subject: b43legacy: Fix compile on ARM architecture When b43legacy is compiled on the arm platform, the following errors are seen: CC [M] drivers/net/wireless/b43legacy/xmit.o In file included from include/net/dst.h:11, from drivers/net/wireless/b43legacy/xmit.c:31: include/net/dst_ops.h:28: error: expected ':', ',', ';', '}' or '__attribute__' before '____cacheline_aligned_in_smp' include/net/dst_ops.h: In function 'dst_entries_get_fast': include/net/dst_ops.h:33: error: 'struct dst_ops' has no member named 'pcpuc_entries' include/net/dst_ops.h: In function 'dst_entries_get_slow': include/net/dst_ops.h:41: error: 'struct dst_ops' has no member named 'pcpuc_entries' include/net/dst_ops.h: In function 'dst_entries_add': include/net/dst_ops.h:49: error: 'struct dst_ops' has no member named 'pcpuc_entries' include/net/dst_ops.h: In function 'dst_entries_init': include/net/dst_ops.h:55: error: 'struct dst_ops' has no member named 'pcpuc_entries' include/net/dst_ops.h: In function 'dst_entries_destroy': include/net/dst_ops.h:60: error: 'struct dst_ops' has no member named 'pcpuc_entries' make[4]: *** [drivers/net/wireless/b43legacy/xmit.o] Error 1 make[3]: *** [drivers/net/wireless/b43legacy] Error 2 make[2]: *** [drivers/net/wireless] Error 2 make[1]: *** [drivers/net] Error 2 make: *** [drivers] Error 2 The cause is a missing include of , which is present for i386 and x86_64 architectures, but not for arm. Signed-off-by: Arnd Hannemann Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- include/net/dst_ops.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h index 1fa5306e3e23..51665b3461b8 100644 --- a/include/net/dst_ops.h +++ b/include/net/dst_ops.h @@ -2,6 +2,7 @@ #define _NET_DST_OPS_H #include #include +#include struct dst_entry; struct kmem_cachep; -- cgit v1.2.3 From 309075cf08ed92a7d2c0e22b7653c5daabbd7ad1 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 12 Nov 2010 08:53:56 +0200 Subject: cfg80211: fix WIPHY_FLAG_IBSS_RSN bit WIPHY_FLAG_IBSS_RSN is BIT(7) as is WIPHY_FLAG_CONTROL_PORT_PROTOCOL. Change to BIT(8). Signed-off-by: Jussi Kivilinna Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2a7936d7851d..97b8b7c9b63c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1355,7 +1355,7 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_AP = BIT(5), WIPHY_FLAG_4ADDR_STATION = BIT(6), WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), - WIPHY_FLAG_IBSS_RSN = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(8), }; struct mac_address { -- cgit v1.2.3 From dfa31fef5dd3d204c4cdae7369f3542bd1f7e84a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 15 Nov 2010 15:11:26 +0100 Subject: carl9170: fix usb anchor wait timeout usb_wait_anchor_empty_timeout's @timeout wants milliseconds and not jiffies. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 3317039cd28f..7504ed14c725 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -553,12 +553,12 @@ static int carl9170_usb_flush(struct ar9170 *ar) usb_free_urb(urb); } - ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ); + ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, 1000); if (ret == 0) err = -ETIMEDOUT; /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ); + ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, 1000); if (ret == 0) err = -ETIMEDOUT; -- cgit v1.2.3 From 898213200cbadc570ef4248a6d90430c4a9c2908 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 12 Nov 2010 11:59:31 -0800 Subject: xhci: Fix command ring replay after resume. Andiry's xHCI bus suspend patch introduced the possibly of a host controller replaying old commands on the command ring, if the host successfully restores the registers after a resume. After a resume from suspend, the xHCI driver must restore the registers, including the command ring pointer. I had suggested that Andiry set the command ring pointer to the current command ring dequeue pointer, so that the driver wouldn't have to zero the command ring. Unfortunately, setting the command ring pointer to the current dequeue pointer won't work because the register assumes the pointer is 64-byte aligned, and TRBs on the command ring are 16-byte aligned. The lower seven bits will always be masked off, leading to the written pointer being up to 3 TRBs behind the intended pointer. Here's a log excerpt. On init, the xHCI driver places a vendor-specific command on the command ring: [ 215.750958] xhci_hcd 0000:01:00.0: Vendor specific event TRB type = 48 [ 215.750960] xhci_hcd 0000:01:00.0: NEC firmware version 30.25 [ 215.750962] xhci_hcd 0000:01:00.0: Command ring deq = 0x3781e010 (DMA) When we resume, the command ring dequeue pointer to be written should have been 0x3781e010. Instead, it's 0x3781e000: [ 235.557846] xhci_hcd 0000:01:00.0: // Setting command ring address to 0x3781e001 [ 235.557848] xhci_hcd 0000:01:00.0: `MEM_WRITE_DWORD(3'b000, 64'hffffc900100bc038, 64'h3781e001, 4'hf); [ 235.557850] xhci_hcd 0000:01:00.0: `MEM_WRITE_DWORD(3'b000, 32'hffffc900100bc020, 32'h204, 4'hf); [ 235.557866] usb usb9: root hub lost power or was reset (I can't see the results of this bug because the xHCI restore always fails on this box, and the xHCI driver re-allocates everything.) The fix is to zero the command ring and put the software and hardware enqueue and dequeue pointer back to the beginning of the ring. We do this before the system suspends, to be paranoid and prevent the BIOS from starting the host without clearing the command ring pointer, which might cause the host to muck with stale memory. (The pointer isn't required to be in the suspend power well, but it could be.) The command ring pointer is set again after the host resumes. Signed-off-by: Sarah Sharp Tested-by: Andiry Xu --- drivers/usb/host/xhci.c | 71 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7c8d70fbe113..06fca0835b52 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -577,6 +577,65 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); } +static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) +{ + u64 val_64; + + /* step 2: initialize command ring buffer */ + val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | + (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue) & + (u64) ~CMD_RING_RSVD_BITS) | + xhci->cmd_ring->cycle_state; + xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", + (long unsigned long) val_64); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); +} + +/* + * The whole command ring must be cleared to zero when we suspend the host. + * + * The host doesn't save the command ring pointer in the suspend well, so we + * need to re-program it on resume. Unfortunately, the pointer must be 64-byte + * aligned, because of the reserved bits in the command ring dequeue pointer + * register. Therefore, we can't just set the dequeue pointer back in the + * middle of the ring (TRBs are 16-byte aligned). + */ +static void xhci_clear_command_ring(struct xhci_hcd *xhci) +{ + struct xhci_ring *ring; + struct xhci_segment *seg; + + ring = xhci->cmd_ring; + seg = ring->deq_seg; + do { + memset(seg->trbs, 0, SEGMENT_SIZE); + seg = seg->next; + } while (seg != ring->deq_seg); + + /* Reset the software enqueue and dequeue pointers */ + ring->deq_seg = ring->first_seg; + ring->dequeue = ring->first_seg->trbs; + ring->enq_seg = ring->deq_seg; + ring->enqueue = ring->dequeue; + + /* + * Ring is now zeroed, so the HW should look for change of ownership + * when the cycle bit is set to 1. + */ + ring->cycle_state = 1; + + /* + * Reset the hardware dequeue pointer. + * Yes, this will need to be re-written after resume, but we're paranoid + * and want to make sure the hardware doesn't access bogus memory + * because, say, the BIOS or an SMI started the host without changing + * the command ring pointers. + */ + xhci_set_cmd_ring_deq(xhci); +} + /* * Stop HC (not bus-specific) * @@ -604,6 +663,7 @@ int xhci_suspend(struct xhci_hcd *xhci) spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } + xhci_clear_command_ring(xhci); /* step 3: save registers */ xhci_save_registers(xhci); @@ -635,7 +695,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - u64 val_64; int old_state, retval; old_state = hcd->state; @@ -648,15 +707,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* step 1: restore register */ xhci_restore_registers(xhci); /* step 2: initialize command ring buffer */ - val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue) & - (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", - (long unsigned long) val_64); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); + xhci_set_cmd_ring_deq(xhci); /* step 3: restore state and start state*/ /* step 3: set CRS flag */ command = xhci_readl(xhci, &xhci->op_regs->command); -- cgit v1.2.3 From e502ac5e1eca99d7dc3f12b2a6780ccbca674858 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:11:45 -0800 Subject: USB: atm: ueagle-atm: fix up some permissions on the sysfs files Some of the sysfs files had the incorrect permissions. Some didn't make sense at all (writable for a file that you could not write to?) Reported-by: Linus Torvalds Cc: Matthieu Castet Cc: Stanislaw Gruszka Cc: Damien Bergamini Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index ea071a5b6eee..44447f54942f 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2301,7 +2301,7 @@ out: return ret; } -static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot); +static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot); static ssize_t read_human_status(struct device *dev, struct device_attribute *attr, char *buf) @@ -2364,8 +2364,7 @@ out: return ret; } -static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO, - read_human_status, NULL); +static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL); static ssize_t read_delin(struct device *dev, struct device_attribute *attr, char *buf) @@ -2397,7 +2396,7 @@ out: return ret; } -static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL); +static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL); #define UEA_ATTR(name, reset) \ \ -- cgit v1.2.3 From 723b991a62d94f74c9f19abd3da6e937288eb969 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:15:11 -0800 Subject: USB: ehci: fix debugfs 'lpm' permissions The permissions for the lpm debugfs file is incorrect, this fixes it. Reported-by: Linus Torvalds Cc: Alek Du Cc: Jacob Pan Cc: David Brownell Cc: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 86afdc73322f..6e2599661b5b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1067,7 +1067,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_registers_fops)) goto file_error; - if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus, + if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus, &debug_lpm_fops)) goto file_error; -- cgit v1.2.3 From d9624e75f6ad94d8a0718c1fafa89186d271a78c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:17:52 -0800 Subject: USB: storage: sierra_ms: fix sysfs file attribute A non-writable sysfs file shouldn't have writable attributes. Reported-by: Linus Torvalds Cc: Kevin Lloyd Cc: Matthew Dharm Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/sierra_ms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 57fc2f532cab..ceba512f84d0 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -121,7 +121,7 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr, } return result; } -static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL); +static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL); int sierra_ms_init(struct us_data *us) { -- cgit v1.2.3 From c990600d340641150f7270470a64bd99a5c0b225 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:32:38 -0800 Subject: USB: misc: cypress_cy7c63: fix up some sysfs attribute permissions They should not be writable by any user. Reported-by: Linus Torvalds Cc: Oliver Bock Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cypress_cy7c63.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index 2f43c57743c9..9251773ecef4 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -196,11 +196,9 @@ static ssize_t get_port1_handler(struct device *dev, return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1); } -static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO, - get_port0_handler, set_port0_handler); +static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler); -static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO, - get_port1_handler, set_port1_handler); +static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler); static int cypress_probe(struct usb_interface *interface, -- cgit v1.2.3 From d489a4b3926bad571d404ca6508f6744b9602776 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:34:26 -0800 Subject: USB: misc: trancevibrator: fix up a sysfs attribute permission It should not be writable by any user. Reported-by: Linus Torvalds Cc: Sam Hocevar Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/trancevibrator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index d77aba46ae85..f63776a48e2a 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -86,7 +86,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed); +static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed); static int tv_probe(struct usb_interface *interface, const struct usb_device_id *id) -- cgit v1.2.3 From 48f115470e68d443436b76b22dad63ffbffd6b97 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:35:49 -0800 Subject: USB: misc: usbled: fix up some sysfs attribute permissions They should not be writable by any user. Reported-by: Linus Torvalds Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 63da2c3c838f..c96f51de1696 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -94,7 +94,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co change_color(led); \ return count; \ } \ -static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value); +static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value); show_set(blue); show_set(red); show_set(green); -- cgit v1.2.3 From e24d7ace4e822debcb78386bf279c9aba4d7fbd1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:36:44 -0800 Subject: USB: misc: usbsevseg: fix up some sysfs attribute permissions They should not be writable by any user. Reported-by: Linus Torvalds Cc: Harrison Metzger Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbsevseg.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index de8ef945b536..417b8f207e8b 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -192,7 +192,7 @@ static ssize_t set_attr_##name(struct device *dev, \ \ return count; \ } \ -static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name); +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name); static ssize_t show_attr_text(struct device *dev, struct device_attribute *attr, char *buf) @@ -223,7 +223,7 @@ static ssize_t set_attr_text(struct device *dev, return count; } -static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text); +static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text); static ssize_t show_attr_decimals(struct device *dev, struct device_attribute *attr, char *buf) @@ -272,8 +272,7 @@ static ssize_t set_attr_decimals(struct device *dev, return count; } -static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO, - show_attr_decimals, set_attr_decimals); +static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals); static ssize_t show_attr_textmode(struct device *dev, struct device_attribute *attr, char *buf) @@ -319,8 +318,7 @@ static ssize_t set_attr_textmode(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO, - show_attr_textmode, set_attr_textmode); +static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode); MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); -- cgit v1.2.3 From 3d965875144b905d71dfb4d291c665c0794222c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Nov 2010 11:37:55 -0800 Subject: USB: OTG: langwell_otg: fix up some sysfs attribute permissions They should not be writable by any user. Reported-by: Linus Torvalds Cc: Hao Wu Cc: Alan Cox Cc: Alek Du Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/otg/langwell_otg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c index bdc3ea66be69..9fea48264fa2 100644 --- a/drivers/usb/otg/langwell_otg.c +++ b/drivers/usb/otg/langwell_otg.c @@ -1896,7 +1896,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); static ssize_t get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) @@ -1942,8 +1942,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, - get_a_bus_drop, set_a_bus_drop); +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop); static ssize_t get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) @@ -1988,7 +1987,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); static ssize_t set_a_clr_err(struct device *dev, struct device_attribute *attr, @@ -2012,7 +2011,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); static struct attribute *inputs_attrs[] = { &dev_attr_a_bus_req.attr, -- cgit v1.2.3 From 6f07d31e46639e4b1b23de6ee88c9e079a7bf32d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 15 Nov 2010 13:33:25 -0800 Subject: Input: aiptek - tighten up permissions on sysfs attributes Sysfs attributes affecting device behavior should not be, by default, world-writeable. If distributions want to allow console users access these attributes they need to employ udev and friends to adjust permissions as needed. Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/aiptek.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 57b25b84d1fc..0a619c558bfb 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1097,7 +1097,7 @@ store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(pointer_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletPointerMode, store_tabletPointerMode); /*********************************************************************** @@ -1134,7 +1134,7 @@ store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, co } static DEVICE_ATTR(coordinate_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletCoordinateMode, store_tabletCoordinateMode); /*********************************************************************** @@ -1176,7 +1176,7 @@ store_tabletToolMode(struct device *dev, struct device_attribute *attr, const ch } static DEVICE_ATTR(tool_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletToolMode, store_tabletToolMode); /*********************************************************************** @@ -1219,7 +1219,7 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(xtilt, - S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt); + S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt); /*********************************************************************** * support routines for the 'ytilt' file. Note that this file @@ -1261,7 +1261,7 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(ytilt, - S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt); + S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt); /*********************************************************************** * support routines for the 'jitter' file. Note that this file @@ -1288,7 +1288,7 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(jitter, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletJitterDelay, store_tabletJitterDelay); /*********************************************************************** @@ -1317,7 +1317,7 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(delay, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletProgrammableDelay, store_tabletProgrammableDelay); /*********************************************************************** @@ -1406,7 +1406,7 @@ store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_upper, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusUpper, store_tabletStylusUpper); /*********************************************************************** @@ -1437,7 +1437,7 @@ store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_lower, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusLower, store_tabletStylusLower); /*********************************************************************** @@ -1475,7 +1475,7 @@ store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const c } static DEVICE_ATTR(mouse_left, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseLeft, store_tabletMouseLeft); /*********************************************************************** @@ -1505,7 +1505,7 @@ store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_middle, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseMiddle, store_tabletMouseMiddle); /*********************************************************************** @@ -1535,7 +1535,7 @@ store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_right, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseRight, store_tabletMouseRight); /*********************************************************************** @@ -1567,7 +1567,7 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(wheel, - S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel); + S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel); /*********************************************************************** * support routines for the 'execute' file. Note that this file @@ -1600,7 +1600,7 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha } static DEVICE_ATTR(execute, - S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute); + S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute); /*********************************************************************** * support routines for the 'odm_code' file. Note that this file -- cgit v1.2.3 From 4c62ab9c538bc09c38093fa079e6902ea4d42b98 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 16 Nov 2010 09:50:47 -0800 Subject: irda: irttp: allow zero byte packets Sending zero byte packets is not neccessarily an error (AF_INET accepts it, too), so just apply a shortcut. This was discovered because of a non-working software with WINE. See http://bugs.winehq.org/show_bug.cgi?id=19397#c86 http://thread.gmane.org/gmane.linux.irda.general/1643 for very detailed debugging information and a testcase. Kudos to Wolfgang for those! Reported-by: Wolfgang Schwotzer Signed-off-by: Wolfram Sang Tested-by: Mike Evans Signed-off-by: David S. Miller --- net/irda/irttp.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 285761e77d90..6cfaeaf2a370 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -550,16 +550,23 @@ EXPORT_SYMBOL(irttp_close_tsap); */ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) { + int ret = -1; + IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); IRDA_DEBUG(4, "%s()\n", __func__); + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + /* Check that nothing bad happens */ - if ((skb->len == 0) || (!self->connected)) { - IRDA_DEBUG(1, "%s(), No data, or not connected\n", - __func__); + if (!self->connected) { + IRDA_DEBUG(1, "%s(), Not connected\n", __func__); goto err; } @@ -576,7 +583,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) err: dev_kfree_skb(skb); - return -1; + return ret; } EXPORT_SYMBOL(irttp_udata_request); @@ -599,9 +606,15 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__, skb_queue_len(&self->tx_queue)); + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + /* Check that nothing bad happens */ - if ((skb->len == 0) || (!self->connected)) { - IRDA_WARNING("%s: No data, or not connected\n", __func__); + if (!self->connected) { + IRDA_WARNING("%s: Not connected\n", __func__); ret = -ENOTCONN; goto err; } -- cgit v1.2.3 From 744f9f104ea262de1dc3e29265870c649f0d9473 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 13 Nov 2010 11:44:39 -0500 Subject: xen: fix header export to userspace scripts/headers_install.pl prevents "__user" from being exported to userspace headers, so just use compiler.h to make sure that __user is defined and avoid the error. unifdef: linux-next-20101112/xx64/usr/include/xen/privcmd.h.tmp: 79: Premature EOF (#if line 33 depth 1) Signed-off-by: Randy Dunlap Cc: Jeremy Fitzhardinge Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xensource.com (moderated for non-subscribers) Cc: virtualization@lists.osdl.org Cc: Tony Finch Signed-off-by: Jeremy Fitzhardinge --- include/xen/privcmd.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/xen/privcmd.h b/include/xen/privcmd.h index b42cdfd92fee..17857fb4d550 100644 --- a/include/xen/privcmd.h +++ b/include/xen/privcmd.h @@ -34,13 +34,10 @@ #define __LINUX_PUBLIC_PRIVCMD_H__ #include +#include typedef unsigned long xen_pfn_t; -#ifndef __user -#define __user -#endif - struct privcmd_hypercall { __u64 op; __u64 arg[5]; -- cgit v1.2.3 From fe61f1d737f7804e0bd440ace9724e669e2c2906 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 16 Nov 2010 11:06:46 -0800 Subject: xen/xenfs: update xenfs_mount for new prototype .mount now returns a struct dentry *. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index f6339d11d59c..990ee42167a1 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -121,9 +121,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) return rc; } -static int xenfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static struct dentry *xenfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { return mount_single(fs_type, flags, data, xenfs_fill_super); } -- cgit v1.2.3 From 7d98ffd8c2d1da6cec5d84eba42c4aa836a93f85 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Fri, 5 Nov 2010 01:39:12 +0000 Subject: xfrm: update flowi saddr in icmp_send if unset otherwise xfrm_lookup will fail to find correct policy Signed-off-by: Ulrich Weber Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 96bc7f9475a3..e5d1a44bcbdf 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -569,6 +569,9 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) /* No need to clone since we're just using its address. */ rt2 = rt; + if (!fl.nl_u.ip4_u.saddr) + fl.nl_u.ip4_u.saddr = rt->rt_src; + err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0); switch (err) { case 0: -- cgit v1.2.3 From e8364bb8d041c0fd92d69a17ff19f535e1d1c187 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 10 Nov 2010 15:11:07 +0530 Subject: ath9k: Remove pm_qos request after hw unregister. Update pm_qos before removing it in deinit_device to prevent this warning: pm_qos_update_request() called for unknown object. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 6a0d99eff404..92bc5c5f4876 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -817,8 +817,6 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_wakeup(sc); - pm_qos_remove_request(&ath9k_pm_qos_req); - wiphy_rfkill_stop_polling(sc->hw->wiphy); ath_deinit_leds(sc); @@ -832,6 +830,7 @@ void ath9k_deinit_device(struct ath_softc *sc) } ieee80211_unregister_hw(hw); + pm_qos_remove_request(&ath9k_pm_qos_req); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); -- cgit v1.2.3 From 32b089558c54792028f14ae830ca7c0a8d9ac9a3 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:24 +0530 Subject: ath9k_htc: Update usb device ID list Added new VID/PIDs into supported devices list Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f7ec31b4ddd3..0e1227769e9f 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -36,8 +36,13 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */ + { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ + { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ + { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */ { }, }; -- cgit v1.2.3 From 7cbf2611dac8d5f76fe64795a9426b8c97e6c3f8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:25 +0530 Subject: ath9k_htc: Add new devices into AR7010 Treat new PIDs (0xA704, 0x1200) as AR7010 devices. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 4 ++++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 ++ drivers/net/wireless/ath/ath9k/reg.h | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 0e1227769e9f..dfb6560dab92 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -811,6 +811,8 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: firm_offset = AR7010_FIRMWARE_TEXT; break; default: @@ -933,6 +935,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; else diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 3d7b97f1b3ae..7c8a38d04561 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -249,6 +249,8 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: priv->htc->credits = 45; break; default: diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fa05b711e5cd..52ee82d6796b 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -866,7 +866,9 @@ #define AR_DEVID_7010(_ah) \ (((_ah)->hw_version.devid == 0x7010) || \ ((_ah)->hw_version.devid == 0x7015) || \ - ((_ah)->hw_version.devid == 0x9018)) + ((_ah)->hw_version.devid == 0x9018) || \ + ((_ah)->hw_version.devid == 0xA704) || \ + ((_ah)->hw_version.devid == 0x1200)) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 -- cgit v1.2.3 From b5261cf4f3860bd772346a3e692683b6144dd44c Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:26 +0530 Subject: ath9k_hw: Set proper eeprom offset for AR9287 HTC devices AR9287 based PCI & USB devices are differed in eeprom start offset. So set proper the offset for HTC devices to read nvram correctly. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 966b9496a9dd..195406db3bd8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -37,7 +37,7 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) int addr, eep_start_loc; eep_data = (u16 *)eep; - if (ah->hw_version.devid == 0x7015) + if (AR9287_HTC_DEVID(ah)) eep_start_loc = AR9287_HTC_EEP_START_LOC; else eep_start_loc = AR9287_EEP_START_LOC; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 52ee82d6796b..dddf579aacf1 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -870,6 +870,10 @@ ((_ah)->hw_version.devid == 0xA704) || \ ((_ah)->hw_version.devid == 0x1200)) +#define AR9287_HTC_DEVID(_ah) \ + (((_ah)->hw_version.devid == 0x7015) || \ + ((_ah)->hw_version.devid == 0x1200)) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 -- cgit v1.2.3 From 9236d838c920e90708570d9bbd7bb82d30a38130 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 12 Nov 2010 16:31:23 -0800 Subject: cfg80211: fix extension channel checks to initiate communication When operating in a mode that initiates communication and using HT40 we should fail if we cannot use both primary and secondary channels to initiate communication. Our current ht40 allowmap only covers STA mode of operation, for beaconing modes we need a check on the fly as the mode of operation is dynamic and there other flags other than disable which we should read to check if we can initiate communication. Do not allow for initiating communication if our secondary HT40 channel has is either disabled, has a passive scan flag, a no-ibss flag or is a radar channel. Userspace now has similar checks but this is also needed in-kernel. Reported-by: Jouni Malinen Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/chan.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d0c92dddb26b..c8d190d911e4 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -44,6 +44,36 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, return chan; } +static bool can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *sec_chan; + int diff; + + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + diff = 20; + case NL80211_CHAN_HT40MINUS: + diff = -20; + default: + return false; + } + + sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); + if (!sec_chan) + return false; + + /* we'll need a DFS capability later */ + if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR)) + return false; + + return true; +} + int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type) @@ -68,6 +98,28 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, if (!chan) return -EINVAL; + /* Both channels should be able to initiate communication */ + if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || + wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_AP_VLAN || + wdev->iftype == NL80211_IFTYPE_MESH_POINT || + wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + case NL80211_CHAN_HT40MINUS: + if (!can_beacon_sec_chan(&rdev->wiphy, chan, + channel_type)) { + printk(KERN_DEBUG + "cfg80211: Secondary channel not " + "allowed to initiate communication\n"); + return -EINVAL; + } + break; + default: + break; + } + } + result = rdev->ops->set_channel(&rdev->wiphy, wdev ? wdev->netdev : NULL, chan, channel_type); -- cgit v1.2.3 From 3d091a6f703906c5680855ff29bd94d051c8c6d8 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 8 Nov 2010 17:58:35 +0800 Subject: USB: EHCI: AMD periodic frame list table quirk On AMD SB700/SB800/Hudson-2/3 platforms, USB EHCI controller may read/write to memory space not allocated to USB controller if there is longer than normal latency on DMA read encountered. In this condition the exposure will be encountered only if the driver has following format of Periodic Frame List link pointer structure: For any idle periodic schedule, the Frame List link pointers that have the T-bit set to 1 intending to terminate the use of frame list link pointer as a physical memory pointer. Idle periodic schedule Frame List Link pointer shoule be in the following format to avoid the issue: Frame list link pointer should be always contains a valid pointer to a inactive QHead with T-bit set to 0. Signed-off-by: Andiry Xu Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mem.c | 26 ++++++++++++++++++++++++-- drivers/usb/host/ehci-pci.c | 13 +++++++++++++ drivers/usb/host/ehci-sched.c | 21 ++++++++++++++++++--- drivers/usb/host/ehci.h | 2 ++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index d36e4e75e08d..12f70c302b0b 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) qh_put (ehci->async); ehci->async = NULL; + if (ehci->dummy) + qh_put(ehci->dummy); + ehci->dummy = NULL; + /* DMA consistent memory and pools */ if (ehci->qtd_pool) dma_pool_destroy (ehci->qtd_pool); @@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) if (ehci->periodic == NULL) { goto fail; } - for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic [i] = EHCI_LIST_END(ehci); + + if (ehci->use_dummy_qh) { + struct ehci_qh_hw *hw; + ehci->dummy = ehci_qh_alloc(ehci, flags); + if (!ehci->dummy) + goto fail; + + hw = ehci->dummy->hw; + hw->hw_next = EHCI_LIST_END(ehci); + hw->hw_qtd_next = EHCI_LIST_END(ehci); + hw->hw_alt_next = EHCI_LIST_END(ehci); + hw->hw_token &= ~QTD_STS_ACTIVE; + ehci->dummy->hw = hw; + + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic[i] = ehci->dummy->qh_dma; + } else { + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic[i] = EHCI_LIST_END(ehci); + } /* software shadow of hardware table */ ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a1e8d273103f..01bb72b71832 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -103,6 +103,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd) if (retval) return retval; + if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) || + (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) { + /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may + * read/write memory space which does not belong to it when + * there is NULL pointer with T-bit set to 1 in the frame list + * table. To avoid the issue, the frame list link pointer + * should always contain a valid pointer to a inactive qh. + */ + ehci->use_dummy_qh = 1; + ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI " + "dummy qh workaround\n"); + } + /* data structure init */ retval = ehci_init(hcd); if (retval) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a92526d6e5ae..d9f78eb26572 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) */ *prev_p = *periodic_next_shadow(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); - *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); + + if (!ehci->use_dummy_qh || + *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)) + != EHCI_LIST_END(ehci)) + *hw_p = *shadow_next_periodic(ehci, &here, + Q_NEXT_TYPE(ehci, *hw_p)); + else + *hw_p = ehci->dummy->qh_dma; } /* how many of the uframe's 125 usecs are allocated? */ @@ -2335,7 +2342,11 @@ restart: * pointer for much longer, if at all. */ *q_p = q.itd->itd_next; - *hw_p = q.itd->hw_next; + if (!ehci->use_dummy_qh || + q.itd->hw_next != EHCI_LIST_END(ehci)) + *hw_p = q.itd->hw_next; + else + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.itd->hw_next); wmb(); modified = itd_complete (ehci, q.itd); @@ -2368,7 +2379,11 @@ restart: * URB completion. */ *q_p = q.sitd->sitd_next; - *hw_p = q.sitd->hw_next; + if (!ehci->use_dummy_qh || + q.sitd->hw_next != EHCI_LIST_END(ehci)) + *hw_p = q.sitd->hw_next; + else + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); wmb(); modified = sitd_complete (ehci, q.sitd); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bde823f704e9..ba8eab366b82 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -73,6 +73,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; + struct ehci_qh *dummy; /* For AMD quirk use */ struct ehci_qh *reclaim; unsigned scanning : 1; @@ -131,6 +132,7 @@ struct ehci_hcd { /* one per controller */ unsigned need_io_watchdog:1; unsigned broken_periodic:1; unsigned fs_i_thresh:1; /* Intel iso scheduling */ + unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) -- cgit v1.2.3 From f52022b53bac3228620e490abbe2ccb1e87ab060 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 9 Nov 2010 09:16:39 +0800 Subject: USB: isp1362-hcd - fix section mismatch warning Fix section mismatch warning by using "__devinit" annotation for isp1362_probe. WARNING: drivers/usb/host/isp1362-hcd.o(.data+0x0): Section mismatch in reference from the variable isp1362_driver to the function .init.text:isp1362_probe() The variable isp1362_driver references the function __init isp1362_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, Signed-off-by: Axel Lin Acked-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1362-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 8196fa11fec4..97cce59ff767 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2684,7 +2684,7 @@ static int __devexit isp1362_remove(struct platform_device *pdev) return 0; } -static int __init isp1362_probe(struct platform_device *pdev) +static int __devinit isp1362_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp1362_hcd *isp1362_hcd; -- cgit v1.2.3 From b48809518631880207796b4aab0fc39c2f036754 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 16 Nov 2010 11:51:32 +0100 Subject: USB: gadget: AT91: fix typo in atmel_usba_udc driver compile fix for bug introduced by 969affff547027) Signed-off-by: Josh Wu Cc: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/atmel_usba_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index b5e20e873cba..717ff653fa23 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -2017,7 +2017,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) } } else { /* gpio_request fail so use -EINVAL for gpio_is_valid */ - ubc->vbus_pin = -EINVAL; + udc->vbus_pin = -EINVAL; } } -- cgit v1.2.3 From 02e2c51ba3e80acde600721ea784c3ef84da5ea1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Nov 2010 10:57:37 -0500 Subject: USB: EHCI: fix obscure race in ehci_endpoint_disable This patch (as1435) fixes an obscure and unlikely race in ehci-hcd. When an async URB is unlinked, the corresponding QH is removed from the async list. If the QH's endpoint is then disabled while the URB is being given back, ehci_endpoint_disable() won't find the QH on the async list, causing it to believe that the QH has been lost. This will lead to a memory leak at best and quite possibly to an oops. The solution is to trust usbcore not to lose track of endpoints. If the QH isn't on the async list then it doesn't need to be taken off the list, but the driver should still wait for the QH to become IDLE before disabling it. In theory this fixes Bugzilla #20182. In fact the race is so rare that it's not possible to tell whether the bug is still present. However, adding delays and making other changes to force the race seems to show that the patch works. Signed-off-by: Alan Stern Reported-by: Stefan Richter CC: David Brownell CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 502a7e6fef42..e9062806d4a2 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1063,10 +1063,11 @@ rescan: tmp && tmp != qh; tmp = tmp->qh_next.qh) continue; - /* periodic qh self-unlinks on empty */ - if (!tmp) - goto nogood; - unlink_async (ehci, qh); + /* periodic qh self-unlinks on empty, and a COMPLETING qh + * may already be unlinked. + */ + if (tmp) + unlink_async(ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: @@ -1083,7 +1084,6 @@ idle_timeout: } /* else FALL THROUGH */ default: -nogood: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. */ -- cgit v1.2.3 From 1c6969ec8e6328e8d288fc585310e9e52fc9db04 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 16 Nov 2010 14:55:33 -0800 Subject: xen/evtchn: clear secondary CPUs' cpu_evtchn_mask[] after restore To bind all event channels to CPU#0, it is not sufficient to set all of its cpu_evtchn_mask[] bits; all other CPUs also need to get their bits cleared. Otherwise, evtchn_do_upcall() will start handling interrupts on CPUs they're not intended to run on, which can be particularly bad for per-CPU ones. [ linux-2.6.18-xen.hg 7de7453dee36 ] Signed-off-by: Jan Beulich Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/events.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 321a0c8346e5..d770b8c8885b 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -286,9 +286,9 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) static void init_evtchn_cpu_bindings(void) { + int i; #ifdef CONFIG_SMP struct irq_desc *desc; - int i; /* By default all event channels notify CPU#0. */ for_each_irq_desc(i, desc) { @@ -296,7 +296,10 @@ static void init_evtchn_cpu_bindings(void) } #endif - memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s)); + for_each_possible_cpu(i) + memset(cpu_evtchn_mask(i), + (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s)); + } static inline void clear_evtchn(int port) -- cgit v1.2.3 From e04195644eea7c6c14007922257704ec67156cd1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 16 Nov 2010 14:56:47 -0800 Subject: xen/events: use locked set|clear_bit() for cpu_evtchn_mask The per-cpu event channel masks can be updated unlocked from multiple CPUs, so use the locked variant. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d770b8c8885b..d6d4f76ed500 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -278,8 +278,8 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); #endif - __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); - __set_bit(chn, cpu_evtchn_mask(cpu)); + clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); + set_bit(chn, cpu_evtchn_mask(cpu)); irq_info[irq].cpu = cpu; } -- cgit v1.2.3 From 23e701e6208191ad103517ae7a700f2dc59ab2ec Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 17 Nov 2010 12:03:58 -0500 Subject: [libata] remove SCSI host lock and serial number usage from ata_scsi_queuecmd cmd->serial_number is never tested in any path we reach; therefore we may remove the call to scsi_cmd_get_serial() inside DEF_SCSI_QCMD, the SCSI host_lock acquisition surrounding it, and our own SCSI host_lock unlock+relock cycle. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 19835d39289d..66aa4bee80a6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3166,8 +3166,8 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, /** * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device + * @shost: SCSI host of command to be sent * @cmd: SCSI command to be sent - * @done: Completion function, called when command is complete * * In some cases, this function translates SCSI commands into * ATA taskfiles, and queues the taskfiles to be sent to @@ -3177,42 +3177,39 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, * ATA and ATAPI devices appearing as SCSI devices. * * LOCKING: - * Releases scsi-layer-held lock, and obtains host lock. + * ATA host lock * * RETURNS: * Return value from __ata_scsi_queuecmd() if @cmd can be queued, * 0 otherwise. */ -static int ata_scsi_queuecmd_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) { struct ata_port *ap; struct ata_device *dev; struct scsi_device *scsidev = cmd->device; - struct Scsi_Host *shost = scsidev->host; int rc = 0; + unsigned long irq_flags; ap = ata_shost_to_port(shost); - spin_unlock(shost->host_lock); - spin_lock(ap->lock); + spin_lock_irqsave(ap->lock, irq_flags); ata_scsi_dump_cdb(ap, cmd); dev = ata_scsi_find_dev(ap, scsidev); if (likely(dev)) - rc = __ata_scsi_queuecmd(cmd, done, dev); + rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev); else { cmd->result = (DID_BAD_TARGET << 16); - done(cmd); + cmd->scsi_done(cmd); } - spin_unlock(ap->lock); - spin_lock(shost->host_lock); + spin_unlock_irqrestore(ap->lock, irq_flags); + return rc; } -DEF_SCSI_QCMD(ata_scsi_queuecmd) - /** * ata_scsi_simulate - simulate SCSI command on ATA device * @dev: the target device -- cgit v1.2.3 From 11e713a07e0c03e2202ad1e87cd91d45842ce3da Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Nov 2010 18:39:19 +0000 Subject: ASoC: Fix register cache setup WM8994 for multi-component During the multi-component conversion the WM8994 register cache init got lost. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 0db59c3aa5d4..830dfdd66c5f 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3903,6 +3903,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) return -ENOMEM; snd_soc_codec_set_drvdata(codec, wm8994); + codec->reg_cache = &wm8994->reg_cache; + wm8994->pdata = dev_get_platdata(codec->dev->parent); wm8994->codec = codec; -- cgit v1.2.3 From bedad0ca3fb2ba52c347b54a97b78d32e406dd96 Mon Sep 17 00:00:00 2001 From: Chris Paulson-Ellis Date: Tue, 16 Nov 2010 12:27:09 +0000 Subject: ASoC: davinci: fixes for multi-component Multi-component commit f0fba2ad broke a few things which this patch should fix. Tested on the DM355 EVM. I've been as careful as I can, but it would be good if those with access to other Davinci boards could test. -- The multi-component commit put the initialisation of snd_soc_dai.[capture|playback]_dma_data into snd_soc_dai_ops.hw_params of the McBSP, McASP & VCIF drivers (davinci-i2s.c, davinci-mcasp.c & davinci-vcif.c). The initialisation had to be moved from the probe function in these drivers because davinci_*_dai changed from snd_soc_dai to snd_soc_dai_driver. Unfortunately, the DMA params pointer is needed by davinci_pcm_open (in davinci-pcm.c) before hw_params is called. I have moved the initialisation to a new snd_soc_dai_ops.startup function in each of these drivers. This fix indicates that all platforms that use davinci-pcm must have been broken and need to test with this fix. -- The multi-component commit also changed the McBSP driver name from "davinci-asp" to "davinci-i2s" in davinci-i2s.c without updating the board level references to the driver name. This change is understandable, as there is a similarly named "davinci-mcasp" driver in davinci-mcasp.c. There is probably no 'correct' name for this driver. The DM6446 datasheet calls it the "ASP" and describes it as a "specialised McBSP". The DM355 datasheet calls it the "ASP" and describes it as a "specialised ASP". The DM365 datasheet calls it the "McBSP". Rather than fix this problem by reverting to "davinci-asp", I've elected to avoid future confusion with the "davinci-mcasp" driver by changing it to "davinci-mcbsp", which is also consistent with the names of the functions in the driver. There are other fixes required, so it was never going to be as simple as a revert anyway. -- The DM365 only has one McBSP port (of the McBSP platforms, only the DM355 has 2 ports), so I've changed the the id of the platform_device from 0 to -1. -- In davinci-evm.c, the DM6446 EVM can no longer share a snd_soc_dai_link structure with the DM355 EVM as they use different cpu DAI names (the DM355 has 2 ports and the EVM uses the second port, but the DM6446 only has 1 port). This also means that the 2 boards need different snd_soc_card structures. -- The codec_name entries in davinci-evm.c didn't match the i2c ids in the board files. I have only checked and fixed the details of the names used for the McBSP based platforms. Someone with a McASP based platform (eg DA8xx) should check the others. Signed-off-by: Chris Paulson-Ellis Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/arm/mach-davinci/dm355.c | 6 +++--- arch/arm/mach-davinci/dm365.c | 6 +++--- arch/arm/mach-davinci/dm644x.c | 4 ++-- sound/soc/davinci/davinci-evm.c | 40 +++++++++++++++++++++++++++----------- sound/soc/davinci/davinci-i2s.c | 15 ++++++++++---- sound/soc/davinci/davinci-mcasp.c | 13 ++++++++++--- sound/soc/davinci/davinci-sffsdr.c | 2 +- sound/soc/davinci/davinci-vcif.c | 13 ++++++++++--- 8 files changed, 69 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 9be261beae7d..2652af124acd 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -359,8 +359,8 @@ static struct clk_lookup dm355_clks[] = { CLK(NULL, "uart1", &uart1_clk), CLK(NULL, "uart2", &uart2_clk), CLK("i2c_davinci.1", NULL, &i2c_clk), - CLK("davinci-asp.0", NULL, &asp0_clk), - CLK("davinci-asp.1", NULL, &asp1_clk), + CLK("davinci-mcbsp.0", NULL, &asp0_clk), + CLK("davinci-mcbsp.1", NULL, &asp1_clk), CLK("davinci_mmc.0", NULL, &mmcsd0_clk), CLK("davinci_mmc.1", NULL, &mmcsd1_clk), CLK("spi_davinci.0", NULL, &spi0_clk), @@ -664,7 +664,7 @@ static struct resource dm355_asp1_resources[] = { }; static struct platform_device dm355_asp1_device = { - .name = "davinci-asp", + .name = "davinci-mcbsp", .id = 1, .num_resources = ARRAY_SIZE(dm355_asp1_resources), .resource = dm355_asp1_resources, diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index a12065e87266..c466d710d3c1 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -459,7 +459,7 @@ static struct clk_lookup dm365_clks[] = { CLK(NULL, "usb", &usb_clk), CLK("davinci_emac.1", NULL, &emac_clk), CLK("davinci_voicecodec", NULL, &voicecodec_clk), - CLK("davinci-asp.0", NULL, &asp0_clk), + CLK("davinci-mcbsp", NULL, &asp0_clk), CLK(NULL, "rto", &rto_clk), CLK(NULL, "mjcp", &mjcp_clk), CLK(NULL, NULL, NULL), @@ -922,8 +922,8 @@ static struct resource dm365_asp_resources[] = { }; static struct platform_device dm365_asp_device = { - .name = "davinci-asp", - .id = 0, + .name = "davinci-mcbsp", + .id = -1, .num_resources = ARRAY_SIZE(dm365_asp_resources), .resource = dm365_asp_resources, }; diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 0608dd776a16..9a2376b3137c 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -302,7 +302,7 @@ static struct clk_lookup dm644x_clks[] = { CLK("davinci_emac.1", NULL, &emac_clk), CLK("i2c_davinci.1", NULL, &i2c_clk), CLK("palm_bk3710", NULL, &ide_clk), - CLK("davinci-asp", NULL, &asp_clk), + CLK("davinci-mcbsp", NULL, &asp_clk), CLK("davinci_mmc.0", NULL, &mmcsd_clk), CLK(NULL, "spi", &spi_clk), CLK(NULL, "gpio", &gpio_clk), @@ -580,7 +580,7 @@ static struct resource dm644x_asp_resources[] = { }; static struct platform_device dm644x_asp_device = { - .name = "davinci-asp", + .name = "davinci-mcbsp", .id = -1, .num_resources = ARRAY_SIZE(dm644x_asp_resources), .resource = dm644x_asp_resources, diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 2b07b17a6b2d..bc9e6b0b3f6f 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -157,12 +157,23 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) } /* davinci-evm digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link evm_dai = { +static struct snd_soc_dai_link dm6446_evm_dai = { .name = "TLV320AIC3X", .stream_name = "AIC3X", - .cpu_dai_name = "davinci-mcasp.0", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "tlv320aic3x-hifi", - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-001b", + .platform_name = "davinci-pcm-audio", + .init = evm_aic3x_init, + .ops = &evm_ops, +}; + +static struct snd_soc_dai_link dm355_evm_dai = { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .cpu_dai_name = "davinci-mcbsp.1", + .codec_dai_name = "tlv320aic3x-hifi", + .codec_name = "tlv320aic3x-codec.1-001b", .platform_name = "davinci-pcm-audio", .init = evm_aic3x_init, .ops = &evm_ops, @@ -172,10 +183,10 @@ static struct snd_soc_dai_link dm365_evm_dai = { #ifdef CONFIG_SND_DM365_AIC3X_CODEC .name = "TLV320AIC3X", .stream_name = "AIC3X", - .cpu_dai_name = "davinci-i2s", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "tlv320aic3x-hifi", .init = evm_aic3x_init, - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-0018", .ops = &evm_ops, #elif defined(CONFIG_SND_DM365_VOICE_CODEC) .name = "Voice Codec - CQ93VC", @@ -219,10 +230,17 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .ops = &evm_ops, }; -/* davinci dm6446, dm355 evm audio machine driver */ -static struct snd_soc_card snd_soc_card_evm = { - .name = "DaVinci EVM", - .dai_link = &evm_dai, +/* davinci dm6446 evm audio machine driver */ +static struct snd_soc_card dm6446_snd_soc_card_evm = { + .name = "DaVinci DM6446 EVM", + .dai_link = &dm6446_evm_dai, + .num_links = 1, +}; + +/* davinci dm355 evm audio machine driver */ +static struct snd_soc_card dm355_snd_soc_card_evm = { + .name = "DaVinci DM355 EVM", + .dai_link = &dm355_evm_dai, .num_links = 1, }; @@ -261,10 +279,10 @@ static int __init evm_init(void) int ret; if (machine_is_davinci_evm()) { - evm_snd_dev_data = &snd_soc_card_evm; + evm_snd_dev_data = &dm6446_snd_soc_card_evm; index = 0; } else if (machine_is_davinci_dm355_evm()) { - evm_snd_dev_data = &snd_soc_card_evm; + evm_snd_dev_data = &dm355_snd_soc_card_evm; index = 1; } else if (machine_is_davinci_dm365_evm()) { evm_snd_dev_data = &dm365_snd_soc_card_evm; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d46b545d41f4..9e0e565e6ed9 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -426,9 +426,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t fmt; unsigned element_cnt = 1; - dai->capture_dma_data = dev->dma_params; - dai->playback_dma_data = dev->dma_params; - /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -601,6 +598,15 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int davinci_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -612,6 +618,7 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 static struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .startup = davinci_i2s_startup, .shutdown = davinci_i2s_shutdown, .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, @@ -749,7 +756,7 @@ static struct platform_driver davinci_mcbsp_driver = { .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .driver = { - .name = "davinci-i2s", + .name = "davinci-mcbsp", .owner = THIS_MODULE, }, }; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 86918ee12419..fb55d2c5d704 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -715,9 +715,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int word_length; u8 fifo_level; - cpu_dai->capture_dma_data = dev->dma_params; - cpu_dai->playback_dma_data = dev->dma_params; - davinci_hw_common_param(dev, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fifo_level = dev->txnumevt; @@ -799,7 +796,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, return ret; } +static int davinci_mcasp_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + static struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .startup = davinci_mcasp_startup, .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 009b6521a1bf..6c6666a1f942 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -84,7 +84,7 @@ static struct snd_soc_ops sffsdr_ops = { static struct snd_soc_dai_link sffsdr_dai = { .name = "PCM3008", /* Codec name */ .stream_name = "PCM3008 HiFi", - .cpu_dai_name = "davinci-asp.0", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "pcm3008-hifi", .codec_name = "pcm3008-codec", .platform_name = "davinci-pcm-audio", diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index ea232f6a2c21..fb4cc1edf339 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -97,9 +97,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, &davinci_vcif_dev->dma_params[substream->stream]; u32 w; - dai->capture_dma_data = davinci_vcif_dev->dma_params; - dai->playback_dma_data = davinci_vcif_dev->dma_params; - /* Restart the codec before setup */ davinci_vcif_stop(substream); davinci_vcif_start(substream); @@ -174,9 +171,19 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int davinci_vcif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + #define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000 static struct snd_soc_dai_ops davinci_vcif_dai_ops = { + .startup = davinci_vcif_startup, .trigger = davinci_vcif_trigger, .hw_params = davinci_vcif_hw_params, }; -- cgit v1.2.3 From 85e76ab50aecbdc9011806f2f8943450ccb0d93c Mon Sep 17 00:00:00 2001 From: Jovi Zhang Date: Wed, 10 Nov 2010 07:22:18 -0600 Subject: kdb: fix memory leak in kdb_main.c Call kfree in the error path as well as the success path in kdb_ll(). Signed-off-by: Jovi Zhang Signed-off-by: Jason Wessel --- kernel/debug/kdb/kdb_main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 37755d621924..3ab3feee7840 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2361,7 +2361,7 @@ static int kdb_pid(int argc, const char **argv) */ static int kdb_ll(int argc, const char **argv) { - int diag; + int diag = 0; unsigned long addr; long offset = 0; unsigned long va; @@ -2400,20 +2400,21 @@ static int kdb_ll(int argc, const char **argv) char buf[80]; if (KDB_FLAG(CMD_INTERRUPT)) - return 0; + goto out; sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va); diag = kdb_parse(buf); if (diag) - return diag; + goto out; addr = va + linkoffset; if (kdb_getword(&va, addr, sizeof(va))) - return 0; + goto out; } - kfree(command); - return 0; +out: + kfree(command); + return diag; } static int kdb_kgdb(int argc, const char **argv) -- cgit v1.2.3 From 5450d904054b4ed582793ad6ecb5469f03cc4c46 Mon Sep 17 00:00:00 2001 From: Jovi Zhang Date: Wed, 10 Nov 2010 07:22:18 -0600 Subject: kdb: fix crash when KDB_BASE_CMD_MAX is exceeded When the number of dyanmic kdb commands exceeds KDB_BASE_CMD_MAX, the kernel will fault. Signed-off-by: Jovi Zhang Signed-off-by: Jason Wessel --- kernel/debug/kdb/kdb_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 3ab3feee7840..a6e729766821 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -82,7 +82,7 @@ static kdbtab_t kdb_base_commands[50]; #define for_each_kdbcmd(cmd, num) \ for ((cmd) = kdb_base_commands, (num) = 0; \ num < kdb_max_commands; \ - num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++, num++) + num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++) typedef struct _kdbmsg { int km_diag; /* kdb diagnostic */ @@ -646,7 +646,7 @@ static int kdb_defcmd2(const char *cmdstr, const char *argv0) } if (!s->usable) return KDB_NOTIMP; - s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); + s->command = kzalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); if (!s->command) { kdb_printf("Could not allocate new kdb_defcmd table for %s\n", cmdstr); @@ -2740,13 +2740,13 @@ int kdb_register_repeat(char *cmd, } if (kdb_commands) { memcpy(new, kdb_commands, - kdb_max_commands * sizeof(*new)); + (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new)); kfree(kdb_commands); } memset(new + kdb_max_commands, 0, kdb_command_extend * sizeof(*new)); kdb_commands = new; - kp = kdb_commands + kdb_max_commands; + kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX; kdb_max_commands += kdb_command_extend; } -- cgit v1.2.3 From 10a6e67648d4b47769953bd24759ba9609bf00df Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 15 Nov 2010 08:07:35 -0600 Subject: kgdb,x86: fix regression in detach handling The fix from ba773f7c510c0b252145933926c636c439889207 (x86,kgdb: Fix hw breakpoint regression) was not entirely complete. The kgdb_remove_all_hw_break() function also needs to call the hw_break_release_slot() or else a breakpoint can get activated again after the debugger has detached. The kgdb test suite exposes the behavior in the form of either a hang or repetitive failure. The kernel config that exposes the problem contains all of the following: CONFIG_DEBUG_RODATA=y CONFIG_KGDB_TESTS=y CONFIG_KGDB_TESTS_ON_BOOT=y CONFIG_KGDB_TESTS_BOOT_STRING="V1F100" Reported-by: Frederic Weisbecker Signed-off-by: Jason Wessel Tested-by: Frederic Weisbecker --- arch/x86/kernel/kgdb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index ec592caac4b4..cd21b654dec6 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -315,14 +315,18 @@ static void kgdb_remove_all_hw_break(void) if (!breakinfo[i].enabled) continue; bp = *per_cpu_ptr(breakinfo[i].pev, cpu); - if (bp->attr.disabled == 1) + if (!bp->attr.disabled) { + arch_uninstall_hw_breakpoint(bp); + bp->attr.disabled = 1; continue; + } if (dbg_is_early) early_dr7 &= ~encode_dr7(i, breakinfo[i].len, breakinfo[i].type); - else - arch_uninstall_hw_breakpoint(bp); - bp->attr.disabled = 1; + else if (hw_break_release_slot(i)) + printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n", + breakinfo[i].addr); + breakinfo[i].enabled = 0; } } -- cgit v1.2.3 From e3839ed8e89e79202c0402ac46965c0686897890 Mon Sep 17 00:00:00 2001 From: Dongdong Deng Date: Tue, 16 Nov 2010 16:02:00 -0600 Subject: kgdb,ppc: Fix regression in evr register handling Commit ff10b88b5a05c8f1646dd15fb9f6093c1384ff6d (kgdb,ppc: Individual register get/set for ppc) introduced a problem where memcpy was used incorrectly to read and write the evr registers with a kernel that has: CONFIG_FSL_BOOKE=y CONFIG_SPE=y CONFIG_KGDB=y This patch also fixes the following compilation problems: arch/powerpc/kernel/kgdb.c: In function 'dbg_get_reg': arch/powerpc/kernel/kgdb.c:341: error: passing argument 2 of 'memcpy' makes pointer from integer without a cast arch/powerpc/kernel/kgdb.c: In function 'dbg_set_reg': arch/powerpc/kernel/kgdb.c:366: error: passing argument 1 of 'memcpy' makes pointer from integer without a cast [jason.wessel@windriver.com: Remove void * casts and fix patch header] Reported-by: Milton Miller Signed-off-by: Dongdong Deng Acked-by: Kumar Gala Signed-off-by: Jason Wessel CC: linuxppc-dev@lists.ozlabs.org --- arch/powerpc/kernel/kgdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 7a9db64f3f04..42850ee00ada 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -337,7 +337,7 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) /* FP registers 32 -> 63 */ #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) if (current) - memcpy(mem, current->thread.evr[regno-32], + memcpy(mem, ¤t->thread.evr[regno-32], dbg_reg_def[regno].size); #else /* fp registers not used by kernel, leave zero */ @@ -362,7 +362,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) if (regno >= 32 && regno < 64) { /* FP registers 32 -> 63 */ #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) - memcpy(current->thread.evr[regno-32], mem, + memcpy(¤t->thread.evr[regno-32], mem, dbg_reg_def[regno].size); #else /* fp registers not used by kernel, leave zero */ -- cgit v1.2.3 From 218854af84038d828a32f061858b1902ed2beec6 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 17 Nov 2010 06:37:16 +0000 Subject: rds: Integer overflow in RDS cmsg handling In rds_cmsg_rdma_args(), the user-provided args->nr_local value is restricted to less than UINT_MAX. This seems to need a tighter upper bound, since the calculation of total iov_size can overflow, resulting in a small sock_kmalloc() allocation. This would probably just result in walking off the heap and crashing when calling rds_rdma_pages() with a high count value. If it somehow doesn't crash here, then memory corruption could occur soon after. Signed-off-by: Dan Rosenberg Signed-off-by: David S. Miller --- net/rds/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 8920f2a83327..4e37c1cbe8b2 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -567,7 +567,7 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, goto out; } - if (args->nr_local > (u64)UINT_MAX) { + if (args->nr_local > UIO_MAXIOV) { ret = -EMSGSIZE; goto out; } -- cgit v1.2.3 From d5d3ebe3be5c5123f2d444e186717f45284151e2 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Fri, 12 Nov 2010 00:15:25 +0000 Subject: r8169: fix checksum broken If r8196 received packets with invalid sctp/igmp(not tcp, udp) checksum, r8196 set skb->ip_summed wit CHECKSUM_UNNECESSARY. This cause that upper protocol don't check checksum field. I am not family with r8196 driver. I try to guess the meaning of RxProtoIP and IPFail. RxProtoIP stands for received IPv4 packet that upper protocol is not tcp and udp. !(opts1 & IPFail) is true means that driver correctly to check checksum in IPv4 header. If it's right, I think we should not set ip_summed wit CHECKSUM_UNNECESSARY for my sctp packets with invalid checksum. If it's not right, please tell me. Signed-off-by: Shan Wei Acked-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4c4d16905efb..7d33ef4bcb4a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4440,8 +4440,7 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) u32 status = opts1 & RxProtoMask; if (((status == RxProtoTCP) && !(opts1 & TCPFail)) || - ((status == RxProtoUDP) && !(opts1 & UDPFail)) || - ((status == RxProtoIP) && !(opts1 & IPFail))) + ((status == RxProtoUDP) && !(opts1 & UDPFail))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); -- cgit v1.2.3 From 24b7ea9f6c9787fad885442ed0cc010f1aa69cca Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Wed, 17 Nov 2010 11:55:08 -0800 Subject: 8139cp: fix checksum broken I am not family with RealTek RTL-8139C+ series 10/100 PCI Ethernet driver. I try to guess the meaning of RxProtoIP and IPFail. RxProtoIP stands for received IPv4 packet that upper protocol is not tcp and udp. !(status & IPFail) is true means that driver correctly to check checksum in IPv4 header. If these are right, driver will set ip_summed with CHECKSUM_UNNECESSARY for other upper protocol, e.g. sctp, igmp protocol. This will cause protocol stack ignores checksum check for packets with invalid checksum. This patch is only compile-test. Signed-off-by: Shan Wei Signed-off-by: David S. Miller --- drivers/net/8139cp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ac422cd332ea..dd16e83933a2 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -490,13 +490,11 @@ static inline unsigned int cp_rx_csum_ok (u32 status) { unsigned int protocol = (status >> 16) & 0x3; - if (likely((protocol == RxProtoTCP) && (!(status & TCPFail)))) + if (((protocol == RxProtoTCP) && !(status & TCPFail)) || + ((protocol == RxProtoUDP) && !(status & UDPFail))) return 1; - else if ((protocol == RxProtoUDP) && (!(status & UDPFail))) - return 1; - else if ((protocol == RxProtoIP) && (!(status & IPFail))) - return 1; - return 0; + else + return 0; } static int cp_rx_poll(struct napi_struct *napi, int budget) -- cgit v1.2.3 From 870634b0b641271acb2e22df06ddda0c794b89a3 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 14 Nov 2010 10:08:34 +0000 Subject: net: bnx2x: fix error value sign bnx2x_init_one() should return negative value on error. By mistake it returns ENODEV instead of -ENODEV. Signed-off-by: Vasiliy Kulikov Acked-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index e9ad16f00b56..9709b8569666 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -9064,7 +9064,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, default: pr_err("Unknown board_type (%ld), aborting\n", ent->driver_data); - return ENODEV; + return -ENODEV; } cid_count += CNIC_CONTEXT_USE; -- cgit v1.2.3 From 28cb6ccd2c7e86b3a4db94c7062cd27937bed424 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Mon, 15 Nov 2010 10:59:42 +0000 Subject: gianfar: fix signedness issue irq_of_parse_and_map() has an unsigned return type. Testing for a negative error value doesn't work here. Signed-off-by: Nicolas Kaiser Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 49e4ce1246a7..d1bec6269173 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -577,11 +577,10 @@ static int gfar_parse_group(struct device_node *np, irq_of_parse_and_map(np, 1); priv->gfargrp[priv->num_grps].interruptError = irq_of_parse_and_map(np,2); - if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 || - priv->gfargrp[priv->num_grps].interruptReceive < 0 || - priv->gfargrp[priv->num_grps].interruptError < 0) { + if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ || + priv->gfargrp[priv->num_grps].interruptReceive == NO_IRQ || + priv->gfargrp[priv->num_grps].interruptError == NO_IRQ) return -EINVAL; - } } priv->gfargrp[priv->num_grps].grp_id = priv->num_grps; -- cgit v1.2.3 From 0a77fe4c188e25917799f2356d4aa5e6d80c39a2 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 19 Oct 2010 18:48:35 +0200 Subject: KVM: Correct ordering of ldt reload wrt fs/gs reload If fs or gs refer to the ldt, they must be reloaded after the ldt. Reorder the code to that effect. Userspace code that uses the ldt with kvm is nonexistent, so this doesn't fix a user-visible bug. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 82e144a4e514..1ca12298ffc7 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3395,6 +3395,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip; load_host_msrs(vcpu); + kvm_load_ldt(ldt_selector); loadsegment(fs, fs_selector); #ifdef CONFIG_X86_64 load_gs_index(gs_selector); @@ -3402,7 +3403,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #else loadsegment(gs, gs_selector); #endif - kvm_load_ldt(ldt_selector); reload_tss(vcpu); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8da0e45ff7c9..6fe7df75bfd4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -839,8 +839,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) ++vmx->vcpu.stat.host_state_reload; vmx->host_state.loaded = 0; - if (vmx->host_state.fs_reload_needed) - loadsegment(fs, vmx->host_state.fs_sel); if (vmx->host_state.gs_ldt_reload_needed) { kvm_load_ldt(vmx->host_state.ldt_sel); #ifdef CONFIG_X86_64 @@ -850,6 +848,8 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) loadsegment(gs, vmx->host_state.gs_sel); #endif } + if (vmx->host_state.fs_reload_needed) + loadsegment(fs, vmx->host_state.fs_sel); reload_tss(); #ifdef CONFIG_X86_64 if (is_long_mode(&vmx->vcpu)) { -- cgit v1.2.3 From c8770e7ba63bb5dd8fe5f9d251275a8fa717fb78 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 11 Nov 2010 12:37:26 +0200 Subject: KVM: VMX: Fix host userspace gsbase corruption We now use load_gs_index() to load gs safely; unfortunately this also changes MSR_KERNEL_GS_BASE, which we managed separately. This resulted in confusion and breakage running 32-bit host userspace on a 64-bit kernel. Fix by - saving guest MSR_KERNEL_GS_BASE before we we reload the host's gs - doing the host save/load unconditionally, instead of only when in guest long mode Things can be cleaned up further, but this is the minmal fix for now. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/vmx.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6fe7df75bfd4..ff21fdda0c53 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -821,10 +821,9 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) #endif #ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); + if (is_long_mode(&vmx->vcpu)) wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); - } #endif for (i = 0; i < vmx->save_nmsrs; ++i) kvm_set_shared_msr(vmx->guest_msrs[i].index, @@ -839,11 +838,14 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) ++vmx->vcpu.stat.host_state_reload; vmx->host_state.loaded = 0; +#ifdef CONFIG_X86_64 + if (is_long_mode(&vmx->vcpu)) + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); +#endif if (vmx->host_state.gs_ldt_reload_needed) { kvm_load_ldt(vmx->host_state.ldt_sel); #ifdef CONFIG_X86_64 load_gs_index(vmx->host_state.gs_sel); - wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs); #else loadsegment(gs, vmx->host_state.gs_sel); #endif @@ -852,10 +854,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) loadsegment(fs, vmx->host_state.fs_sel); reload_tss(); #ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); - wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); - } + wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); #endif if (current_thread_info()->status & TS_USEDFPU) clts(); -- cgit v1.2.3 From 08da1193d2c8c7a25d0cef7f85d0b9f1ad7c583a Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Wed, 17 Nov 2010 21:46:06 -0500 Subject: ext4: fix setting random pages PageUptodate ext4_end_bio calls put_page and kmem_cache_free before calling SetPageUpdate(). This can result in setting the PageUptodate bit on random pages and causes the following BUG: BUG: Bad page state in process rm pfn:52e54 page:ffffea0001222260 count:0 mapcount:0 mapping: (null) index:0x0 arch kernel: page flags: 0x4000000000000008(uptodate) Fix the problem by moving put_io_page() after the SetPageUpdate() call. Thanks to Hugh Dickins for analyzing this problem. Reported-by: Markus Trippelsdorf Tested-by: Markus Trippelsdorf Signed-off-by: Markus Trippelsdorf Signed-off-by: "Theodore Ts'o" --- fs/ext4/page-io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 7f5451cd1d38..beacce11ac50 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -237,8 +237,6 @@ static void ext4_end_bio(struct bio *bio, int error) } while (bh != head); } - put_io_page(io_end->pages[i]); - /* * If this is a partial write which happened to make * all buffers uptodate then we can optimize away a @@ -248,6 +246,8 @@ static void ext4_end_bio(struct bio *bio, int error) */ if (!partial_write) SetPageUptodate(page); + + put_io_page(io_end->pages[i]); } io_end->num_io_pages = 0; inode = io_end->inode; -- cgit v1.2.3 From f4c8cc652d9f70680dd91be60a7a455040d0a282 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Nov 2010 21:46:25 -0500 Subject: ext4: missing unlock in ext4_clear_request_list() If the the li_request_list was empty then it returned with the lock held. Instead of adding a "goto unlock" I just removed that special case and let it go past the empty list_for_each_safe(). Signed-off-by: Dan Carpenter Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 61182fe6254e..ef09d1443d1a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2799,9 +2799,6 @@ static void ext4_clear_request_list(void) struct ext4_li_request *elr; mutex_lock(&ext4_li_info->li_list_mtx); - if (list_empty(&ext4_li_info->li_request_list)) - return; - list_for_each_safe(pos, n, &ext4_li_info->li_request_list) { elr = list_entry(pos, struct ext4_li_request, lr_request); -- cgit v1.2.3 From 0587aa3d11f9769a301b21bff2c3ed8365606b8d Mon Sep 17 00:00:00 2001 From: yangsheng Date: Wed, 17 Nov 2010 21:46:26 -0500 Subject: jbd2: fix /proc/fs/jbd2/ when using an external journal In jbd2_journal_init_dev(), we need make sure the journal structure is fully initialzied before calling jbd2_stats_proc_init(). Reviewed-by: Andreas Dilger Signed-off-by: yangsheng Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c590d155c095..f837ba953529 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -899,6 +899,14 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, /* journal descriptor can store up to n blocks -bzzz */ journal->j_blocksize = blocksize; + journal->j_dev = bdev; + journal->j_fs_dev = fs_dev; + journal->j_blk_offset = start; + journal->j_maxlen = len; + bdevname(journal->j_dev, journal->j_devname); + p = journal->j_devname; + while ((p = strchr(p, '/'))) + *p = '!'; jbd2_stats_proc_init(journal); n = journal->j_blocksize / sizeof(journal_block_tag_t); journal->j_wbufsize = n; @@ -908,14 +916,6 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, __func__); goto out_err; } - journal->j_dev = bdev; - journal->j_fs_dev = fs_dev; - journal->j_blk_offset = start; - journal->j_maxlen = len; - bdevname(journal->j_dev, journal->j_devname); - p = journal->j_devname; - while ((p = strchr(p, '/'))) - *p = '!'; bh = __getblk(journal->j_dev, start, journal->j_blocksize); if (!bh) { -- cgit v1.2.3 From acbfd58e8a1f24ef644a90a90825c3f435b990f5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 18 Nov 2010 14:39:24 +1100 Subject: powerpc: Fix div64 in bootloader The code is missing a fix that went into the main kernel variant (we should try to share that code again at some stage) Reported-by: Albert Cahalan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/boot/div64.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/div64.S b/arch/powerpc/boot/div64.S index 722f360a32a9..d271ab542673 100644 --- a/arch/powerpc/boot/div64.S +++ b/arch/powerpc/boot/div64.S @@ -33,9 +33,10 @@ __div64_32: cntlzw r0,r5 # we are shifting the dividend right li r10,-1 # to make it < 2^32, and shifting srw r10,r10,r0 # the divisor right the same amount, - add r9,r4,r10 # rounding up (so the estimate cannot + addc r9,r4,r10 # rounding up (so the estimate cannot andc r11,r6,r10 # ever be too large, only too small) andc r9,r9,r10 + addze r9,r9 or r11,r5,r11 rotlw r9,r9,r0 rotlw r11,r11,r0 -- cgit v1.2.3 From 01cf6fe8553b0ac649f3323d8da69b51cad8c468 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Thu, 14 Oct 2010 14:48:52 +0000 Subject: powerpc/pseries: Don't override CONFIG_PPC_PSERIES_DEBUG EEH and pci_dlpar #undef DEBUG, but I think they were added before the ability to control this from Kconfig. It's really annoying to only get some of the debug messages from these files. Leave the lpar.c #undef alone as it produces so much output as to make the kernel unusable. Update the Kconfig text to indicate this particular quirk :) Signed-off-by: Nishanth Aravamudan Acked-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/Kconfig | 6 ++++++ arch/powerpc/platforms/pseries/eeh.c | 2 -- arch/powerpc/platforms/pseries/pci_dlpar.c | 2 -- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index c667f0f02c34..3139814f6439 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -47,6 +47,12 @@ config LPARCFG config PPC_PSERIES_DEBUG depends on PPC_PSERIES && PPC_EARLY_DEBUG bool "Enable extra debug logging in platforms/pseries" + help + Say Y here if you want the pseries core to produce a bunch of + debug messages to the system log. Select this if you are having a + problem with the pseries core and want to see more of what is + going on. This does not enable debugging in lpar.c, which must + be manually done due to its verbosity. default y config PPC_SMLPAR diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 34b7dc12e731..17a11c82e6f8 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -21,8 +21,6 @@ * Please address comments and feedback to Linas Vepstas */ -#undef DEBUG - #include #include #include diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 4b7a062dee15..5fcc92a12d3e 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -25,8 +25,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef DEBUG - #include #include #include -- cgit v1.2.3 From 4a89261b02d421cc1bcadaaebb90bb7919db0854 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 10 Nov 2010 12:29:49 +0000 Subject: powerpc/mm: Fix build error in setup_initial_memory_limit arch/powerpc/mm/tlb_nohash.c: In function 'setup_initial_memory_limit': arch/powerpc/mm/tlb_nohash.c:588:29: error: 'ppc64_memblock_base' undeclared (first use in this function) arch/powerpc/mm/tlb_nohash.c:588:29: note: each undeclared identifier is reported only once for each function it appears in Due to a copy/paste typo with the following commit: commit cd3db0c4ca3d237e7ad20f7107216e575705d2b0 Author: Benjamin Herrenschmidt Date: Tue Jul 6 15:39:02 2010 -0700 memblock: Remove rmo_size, burry it in arch/powerpc where it belongs Signed-off-by: Kumar Gala Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/tlb_nohash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 36c0c449a899..2a030d89bbc6 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -585,6 +585,6 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000); /* Finally limit subsequent allocations */ - memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size); + memblock_set_current_limit(first_memblock_base + ppc64_rma_size); } #endif /* CONFIG_PPC64 */ -- cgit v1.2.3 From 234a71a7d64832e4aa8d9b5c80133480b86f6de3 Mon Sep 17 00:00:00 2001 From: kerstin jonsson Date: Fri, 22 Oct 2010 00:17:55 +0000 Subject: powerpc: Set CONFIG_32BIT on ppc32 commit ffe8018c3424892c9590048fc36caa6c3e0c8a76 of the -mm tree fixes the initramfs size calculation for e.g. s390 but breaks it for 32bit architectures which do not define CONFIG_32BIT. This patch fix the problem for PPC32 which will elsewise end up with a __initramfs_size of 0. Signed-off-by: Kerstin Jonsson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b6447190e1a2..e625e9e034ae 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -4,6 +4,10 @@ config PPC32 bool default y if !PPC64 +config 32BIT + bool + default y if PPC32 + config 64BIT bool default y if PPC64 -- cgit v1.2.3 From 1c2c25c78740b2796c7c06640784cb6732fa4907 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 17 Nov 2010 16:32:59 +0000 Subject: powerpc: Fix call to subpage_protection() In: powerpc/mm: Fix pgtable cache cleanup with CONFIG_PPC_SUBPAGE_PROT commit d28513bc7f675d28b479db666d572e078ecf182d Author: David Gibson subpage_protection() was changed to to take an mm rather a pgdir but it didn't change calling site in hashpage_preload(). The change wasn't noticed at compile time since hashpage_preload() used a void* as the parameter to subpage_protection(). This is obviously wrong and can trigger the following crash when CONFIG_SLAB, CONFIG_DEBUG_SLAB, CONFIG_PPC_64K_PAGES CONFIG_PPC_SUBPAGE_PROT are enabled. Freeing unused kernel memory: 704k freed Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6c49b7 Faulting instruction address: 0xc0000000000410f4 cpu 0x2: Vector: 300 (Data Access) at [c00000004233f590] pc: c0000000000410f4: .hash_preload+0x258/0x338 lr: c000000000041054: .hash_preload+0x1b8/0x338 sp: c00000004233f810 msr: 8000000000009032 dar: 6b6b6b6b6b6c49b7 dsisr: 40000000 current = 0xc00000007e2c0070 paca = 0xc000000007fe0500 pid = 1, comm = init enter ? for help [c00000004233f810] c000000000041020 .hash_preload+0x184/0x338 (unreliable) [c00000004233f8f0] c00000000003ed98 .update_mmu_cache+0xb0/0xd0 [c00000004233f990] c000000000157754 .__do_fault+0x48c/0x5dc [c00000004233faa0] c000000000158fd0 .handle_mm_fault+0x508/0xa8c [c00000004233fb90] c0000000006acdd4 .do_page_fault+0x428/0x6ac [c00000004233fe30] c000000000005260 handle_page_fault+0x20/0x74 Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/hash_utils_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 83f534d862db..5e9584405c45 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1123,7 +1123,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, else #endif /* CONFIG_PPC_HAS_HASH_64K */ rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, - subpage_protection(pgdir, ea)); + subpage_protection(mm, ea)); /* Dump some info in case of hash insertion failure, they should * never happen so it is really useful to know if/when they do -- cgit v1.2.3 From 82ae5eaffad40a6d4738e8a57e48dd0d903a9ef0 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 17 Nov 2010 07:20:32 +0000 Subject: powerpc/mm: Fix module instruction tlb fault handling on Book-E 64 We were seeing oops like the following when we did an rmmod on a module: Unable to handle kernel paging request for instruction fetch Faulting instruction address: 0x8000000000008010 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2 P5020 DS last sysfs file: /sys/devices/qman-portals.2/qman-pool.9/uevent Modules linked in: qman_tester(-) NIP: 8000000000008010 LR: c000000000074858 CTR: 8000000000008010 REGS: c00000002e29bab0 TRAP: 0400 Not tainted (2.6.34.6-00744-g2d21f14) MSR: 0000000080029000 CR: 24000448 XER: 00000000 TASK = c00000007a8be600[4987] 'rmmod' THREAD: c00000002e298000 CPU: 1 GPR00: 8000000000008010 c00000002e29bd30 8000000000012798 c00000000035fb28 GPR04: 0000000000000002 0000000000000002 0000000024022428 c000000000009108 GPR08: fffffffffffffffe 800000000000a618 c0000000003c13c8 0000000000000000 GPR12: 0000000022000444 c00000000fffed00 0000000000000000 0000000000000000 GPR16: 00000000100c0000 0000000000000000 00000000100dabc8 0000000010099688 GPR20: 0000000000000000 00000000100cfc28 0000000000000000 0000000010011a44 GPR24: 00000000100017b2 0000000000000000 0000000000000000 0000000000000880 GPR28: c00000000035fb28 800000000000a7b8 c000000000376d80 c0000000003cce50 NIP [8000000000008010] .test_exit+0x0/0x10 [qman_tester] LR [c000000000074858] .SyS_delete_module+0x1f8/0x2f0 Call Trace: [c00000002e29bd30] [c0000000000748b4] .SyS_delete_module+0x254/0x2f0 (unreliable) [c00000002e29be30] [c000000000000580] syscall_exit+0x0/0x2c Instruction dump: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX 38600000 4e800020 60000000 60000000 <4e800020> 60000000 60000000 60000000 ---[ end trace 4f57124939a84dc8 ]--- This appears to be due to checking the wrong permission bits in the instruction_tlb_miss handling if the address that faulted was in vmalloc space. We need to look at the supervisor execute (_PAGE_BAP_SX) bit and not the user bit (_PAGE_BAP_UX/_PAGE_EXEC). Also removed a branch level since it did not appear to be used. Reported-by: Jeffrey Ladouceur Signed-off-by: Kumar Gala Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/tlb_low_64e.S | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index 8b04c54e596f..8526bd9d2aa3 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -138,8 +138,11 @@ cmpldi cr0,r15,0 /* Check for user region */ std r14,EX_TLB_ESR(r12) /* write crazy -1 to frame */ beq normal_tlb_miss + + li r11,_PAGE_PRESENT|_PAGE_BAP_SX /* Base perm */ + oris r11,r11,_PAGE_ACCESSED@h /* XXX replace the RMW cycles with immediate loads + writes */ -1: mfspr r10,SPRN_MAS1 + mfspr r10,SPRN_MAS1 cmpldi cr0,r15,8 /* Check for vmalloc region */ rlwinm r10,r10,0,16,1 /* Clear TID */ mtspr SPRN_MAS1,r10 -- cgit v1.2.3 From 0f6b77ca12bea571e0a97b0588f62aa5f6012d61 Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Tue, 16 Nov 2010 07:55:16 +0000 Subject: powerpc: Update a BKL related comment The commit 5e3d20a remove bkl from startup code so setup_arch() it isn't called with bkl held anymore. Update the comment on top of that function. Fix also a typo. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/setup_64.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2a178b0ebcdf..ce6f61c6f871 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -497,9 +497,8 @@ static void __init emergency_stack_init(void) } /* - * Called into from start_kernel, after lock_kernel has been called. - * Initializes bootmem, which is unsed to manage page allocation until - * mem_init is called. + * Called into from start_kernel this initializes bootmem, which is used + * to manage page allocation until mem_init is called. */ void __init setup_arch(char **cmdline_p) { -- cgit v1.2.3 From da3bd8203082794d26de3a0a6a7d1ee639d07eb1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Oct 2010 15:07:33 +0200 Subject: drm/nouveau: ratelimit IRQ messages There are two messages in the ISR of nouveau which might be printed out hundred times in a second. Ratelimit them. (We need to move nouveau_ratelimit to the top of the file.) Signed-off-by: Jiri Slaby Reviewed-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 6fd51a51c608..b9e1ffed8557 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -42,6 +42,13 @@ #include "nouveau_connector.h" #include "nv50_display.h" +static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); + +static int nouveau_ratelimit(void) +{ + return __ratelimit(&nouveau_ratelimit_state); +} + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -213,11 +220,12 @@ nouveau_fifo_irq_handler(struct drm_device *dev) u32 ib_get = nv_rd32(dev, 0x003334); u32 ib_put = nv_rd32(dev, 0x003330); - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "State 0x%08x Push 0x%08x\n", - chid, ho_get, get, ho_put, put, ib_get, ib_put, - state, push); + chid, ho_get, get, ho_put, put, + ib_get, ib_put, state, push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nv_wr32(dev, 0x003364, 0x00000000); @@ -266,8 +274,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status) { - NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", - status, chid); + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", + status, chid); nv_wr32(dev, NV03_PFIFO_INTR_0, status); status = 0; } @@ -544,13 +553,6 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); } -static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); - -static int nouveau_ratelimit(void) -{ - return __ratelimit(&nouveau_ratelimit_state); -} - static inline void nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) -- cgit v1.2.3 From 907af60b93045ae33b450553167aa8f684252de3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 9 Oct 2010 04:02:09 +0200 Subject: drm/nouveau: Fix sleep while atomic in the semaphore code. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 441b12420bb1..ab1bbfbf266e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -249,6 +249,7 @@ alloc_semaphore(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_semaphore *sema; + int ret; if (!USE_SEMA(dev)) return NULL; @@ -257,10 +258,14 @@ alloc_semaphore(struct drm_device *dev) if (!sema) goto fail; + ret = drm_mm_pre_get(&dev_priv->fence.heap); + if (ret) + goto fail; + spin_lock(&dev_priv->fence.lock); sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); if (sema->mem) - sema->mem = drm_mm_get_block(sema->mem, 4, 0); + sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); spin_unlock(&dev_priv->fence.lock); if (!sema->mem) -- cgit v1.2.3 From 1f5bd44354c878cf8bb0e28a7cb27677e3640c45 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 2 Oct 2010 16:00:35 +0200 Subject: drm/nouveau: Reject modes exceeding the integrated TMDS maximum bandwidth. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Grzesiek Sójka Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 0871495096fa..6208eedc0970 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -641,11 +641,28 @@ nouveau_connector_get_modes(struct drm_connector *connector) return ret; } +static unsigned +get_tmds_link_bandwidth(struct drm_connector *connector) +{ + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct dcb_entry *dcb = nv_connector->detected_encoder->dcb; + + if (dcb->location != DCB_LOC_ON_CHIP || + dev_priv->chipset >= 0x46) + return 165000; + else if (dev_priv->chipset >= 0x40) + return 155000; + else if (dev_priv->chipset >= 0x18) + return 135000; + else + return 112000; +} + static int nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); @@ -663,11 +680,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 400000; break; case OUTPUT_TMDS: - if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || - !nv_encoder->dcb->duallink_possible) - max_clock = 165000; - else - max_clock = 330000; + max_clock = get_tmds_link_bandwidth(connector); + if (nouveau_duallink && nv_encoder->dcb->duallink_possible) + max_clock *= 2; break; case OUTPUT_ANALOG: max_clock = nv_encoder->dcb->crtconf.maxfreq; -- cgit v1.2.3 From 327ceae6643ddafb0c514183f00e7fc8ca6b6e99 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 05:21:59 +0200 Subject: drm/nv04-nv40: Fall back to panel rescaling if we have no usable native mode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the user to set a mode larger than the native one, useful if we had trouble finding the actual native mode (e.g. because it goes above the hardware bandwidth limits). Reported-by: Grzesiek Sójka Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_dfp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index c936403b26e2..ef23550407b5 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); - /* For internal panels and gpu scaling on DVI we need the native mode */ - if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { - if (!nv_connector->native_mode) - return false; + if (!nv_connector->native_mode || + nv_connector->scaling_mode == DRM_MODE_SCALE_NONE || + mode->hdisplay > nv_connector->native_mode->hdisplay || + mode->vdisplay > nv_connector->native_mode->vdisplay) { + nv_encoder->mode = *adjusted_mode; + + } else { nv_encoder->mode = *nv_connector->native_mode; adjusted_mode->clock = nv_connector->native_mode->clock; - } else { - nv_encoder->mode = *adjusted_mode; } return true; -- cgit v1.2.3 From 5eb94fbba39e71f04d629f8197343273b56e25eb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 7 Oct 2010 03:33:15 +0200 Subject: drm/nv11: Fix bad PLL detection false positive. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index bed669a54a2d..b9672a05c411 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) struct pll_lims pll_lim; struct nouveau_pll_vals pv; - uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF; + enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0; - if (get_pll_limits(dev, pllreg, &pll_lim)) + if (get_pll_limits(dev, pll, &pll_lim)) return; - nouveau_hw_get_pllvals(dev, pllreg, &pv); + nouveau_hw_get_pllvals(dev, pll, &pv); if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m && pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n && @@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) pv.M1 = pll_lim.vco1.max_m; pv.N1 = pll_lim.vco1.min_n; pv.log2P = pll_lim.max_usable_log2p; - nouveau_hw_setpll(dev, pllreg, &pv); + nouveau_hw_setpll(dev, pll_lim.reg, &pv); } /* -- cgit v1.2.3 From cbab95db84f2a444d99bec77bac8b9b6ef20d11c Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 11 Oct 2010 03:43:58 +0200 Subject: drm/nouveau: Some random cleanups. Remove some unused/duplicated definitions and make sparse happy again. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 41 +++-------------------------------- drivers/gpu/drm/nouveau/nouveau_irq.c | 19 ++++++++-------- drivers/gpu/drm/nouveau/nouveau_mem.c | 6 ++--- 3 files changed, 16 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3a07e580d27a..135594c44167 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -485,13 +485,13 @@ enum nv04_fp_display_regs { }; struct nv04_crtc_reg { - unsigned char MiscOutReg; /* */ + unsigned char MiscOutReg; uint8_t CRTC[0xa0]; uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; uint8_t Attribute[21]; - unsigned char DAC[768]; /* Internal Colorlookuptable */ + unsigned char DAC[768]; /* PCRTC regs */ uint32_t fb_start; @@ -539,43 +539,9 @@ struct nv04_output_reg { }; struct nv04_mode_state { - uint32_t bpp; - uint32_t width; - uint32_t height; - uint32_t interlace; - uint32_t repaint0; - uint32_t repaint1; - uint32_t screen; - uint32_t scale; - uint32_t dither; - uint32_t extra; - uint32_t fifo; - uint32_t pixel; - uint32_t horiz; - int arbitration0; - int arbitration1; - uint32_t pll; - uint32_t pllB; - uint32_t vpll; - uint32_t vpll2; - uint32_t vpllB; - uint32_t vpll2B; + struct nv04_crtc_reg crtc_reg[2]; uint32_t pllsel; uint32_t sel_clk; - uint32_t general; - uint32_t crtcOwner; - uint32_t head; - uint32_t head2; - uint32_t cursorConfig; - uint32_t cursor0; - uint32_t cursor1; - uint32_t cursor2; - uint32_t timingH; - uint32_t timingV; - uint32_t displayV; - uint32_t crtcSync; - - struct nv04_crtc_reg crtc_reg[2]; }; enum nouveau_card_type { @@ -1239,7 +1205,6 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); -extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index b9e1ffed8557..e2f2d59be3ea 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -209,8 +209,8 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status & NV_PFIFO_INTR_DMA_PUSHER) { - u32 get = nv_rd32(dev, 0x003244); - u32 put = nv_rd32(dev, 0x003240); + u32 dma_get = nv_rd32(dev, 0x003244); + u32 dma_put = nv_rd32(dev, 0x003240); u32 push = nv_rd32(dev, 0x003220); u32 state = nv_rd32(dev, 0x003228); @@ -224,13 +224,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev) NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "State 0x%08x Push 0x%08x\n", - chid, ho_get, get, ho_put, put, - ib_get, ib_put, state, push); + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nv_wr32(dev, 0x003364, 0x00000000); - if (get != put || ho_get != ho_put) { - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put || ho_get != ho_put) { + nv_wr32(dev, 0x003244, dma_put); nv_wr32(dev, 0x003328, ho_put); } else if (ib_get != ib_put) { @@ -239,10 +240,10 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } else { NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " "Put 0x%08x State 0x%08x Push 0x%08x\n", - chid, get, put, state, push); + chid, dma_get, dma_put, state, push); - if (get != put) - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put) + nv_wr32(dev, 0x003244, dma_put); } nv_wr32(dev, 0x003228, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a163c7c612e7..1165c3e68200 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -33,9 +33,9 @@ #include "drmP.h" #include "drm.h" #include "drm_sarea.h" -#include "nouveau_drv.h" -#define MIN(a,b) a < b ? a : b +#include "nouveau_drv.h" +#include "nouveau_pm.h" /* * NV10-NV40 tiling helpers @@ -719,7 +719,7 @@ nouveau_mem_timing_init(struct drm_device *dev) tUNK_19 = 1; tUNK_20 = 0; tUNK_21 = 0; - switch (MIN(recordlen,21)) { + switch (min(recordlen, 21)) { case 21: tUNK_21 = entry[21]; case 20: -- cgit v1.2.3 From 7bb94d26ad62ca1d6b5e11db6e26425785cc46ac Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 11 Oct 2010 03:37:32 +0200 Subject: drm/nouveau: Avoid lock dependency between ramht and ramin spinlocks. The ramht code called some gpuobj functions with the HARDIRQ-safe RAMHT spinlock held, this could potentially lead to a dead lock because ramin_lock is HARDIRQ-unsafe. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_ramht.c | 71 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index 7f16697cc96c..2d8580927ca4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, return -ENOMEM; } +static struct nouveau_ramht_entry * +nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle) +{ + struct nouveau_ramht *ramht = chan ? chan->ramht : NULL; + struct nouveau_ramht_entry *entry; + unsigned long flags; + + if (!ramht) + return NULL; + + spin_lock_irqsave(&ramht->lock, flags); + list_for_each_entry(entry, &ramht->entries, head) { + if (entry->channel == chan && + (!handle || entry->handle == handle)) { + list_del(&entry->head); + spin_unlock_irqrestore(&ramht->lock, flags); + + return entry; + } + } + spin_unlock_irqrestore(&ramht->lock, flags); + + return NULL; +} + static void -nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) +nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; - struct nouveau_ramht_entry *entry, *tmp; + unsigned long flags; u32 co, ho; - list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) { - if (entry->channel != chan || entry->handle != handle) - continue; - - nouveau_gpuobj_ref(NULL, &entry->gpuobj); - list_del(&entry->head); - kfree(entry); - break; - } - + spin_lock_irqsave(&chan->ramht->lock, flags); co = ho = nouveau_ramht_hash_handle(chan, handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && @@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) nv_wo32(ramht, co + 0, 0x00000000); nv_wo32(ramht, co + 4, 0x00000000); instmem->flush(dev); - return; + goto out; } co += 8; @@ -194,17 +210,22 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", chan->id, handle); +out: + spin_unlock_irqrestore(&chan->ramht->lock, flags); } void nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) { - struct nouveau_ramht *ramht = chan->ramht; - unsigned long flags; + struct nouveau_ramht_entry *entry; - spin_lock_irqsave(&ramht->lock, flags); - nouveau_ramht_remove_locked(chan, handle); - spin_unlock_irqrestore(&ramht->lock, flags); + entry = nouveau_ramht_remove_entry(chan, handle); + if (!entry) + return; + + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } struct nouveau_gpuobj * @@ -265,23 +286,19 @@ void nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, struct nouveau_channel *chan) { - struct nouveau_ramht_entry *entry, *tmp; + struct nouveau_ramht_entry *entry; struct nouveau_ramht *ramht; - unsigned long flags; if (ref) kref_get(&ref->refcount); ramht = *ptr; if (ramht) { - spin_lock_irqsave(&ramht->lock, flags); - list_for_each_entry_safe(entry, tmp, &ramht->entries, head) { - if (entry->channel != chan) - continue; - - nouveau_ramht_remove_locked(chan, entry->handle); + while ((entry = nouveau_ramht_remove_entry(chan, 0))) { + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } - spin_unlock_irqrestore(&ramht->lock, flags); kref_put(&ramht->refcount, nouveau_ramht_del); } -- cgit v1.2.3 From 1397b42b5a2e5b3b982078c89f3594c123e3c2b3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 12 Oct 2010 03:17:43 +0200 Subject: drm/nouveau: Reduce severity of the unknown getparam error. Signed-off-by: Francisco Jerez Acked-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ed7757f14083..af2bec36d91b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1051,7 +1051,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, } /* FALLTHRU */ default: - NV_ERROR(dev, "unknown parameter %lld\n", getparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param); return -EINVAL; } @@ -1066,7 +1066,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, switch (setparam->param) { default: - NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param); return -EINVAL; } -- cgit v1.2.3 From f13b32630dda7e583a84a8c535880cff7e4a9bdd Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 06:01:08 +0200 Subject: drm/nouveau: Expose some BO usage flags to userspace. This will be needed for Z compression and to take smarter placement decisions. Signed-off-by: Francisco Jerez Acked-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++----- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +++ drivers/gpu/drm/nouveau/nouveau_gem.c | 36 +++++++++++++++++++-------------- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ drivers/gpu/drm/nouveau/nv50_crtc.c | 4 ++-- include/drm/nouveau_drm.h | 7 +++++++ 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 80353e2b8409..f55dd9145b7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -144,7 +144,8 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; - nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); + nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), + &align, &size); align >>= PAGE_SHIFT; nouveau_bo_placement_set(nvbo, flags, 0); @@ -525,7 +526,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, stride = 16 * 4; height = amount / stride; - if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (new_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -546,7 +548,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); OUT_RING (chan, 1); } - if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (old_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -753,7 +756,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, if (dev_priv->card_type == NV_50) { ret = nv50_mem_vm_bind_linear(dev, offset + dev_priv->vm_vram_base, - new_mem->size, nvbo->tile_flags, + new_mem->size, + nouveau_bo_tile_layout(nvbo), offset); if (ret) return ret; @@ -894,7 +898,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) * nothing to do here. */ if (bo->mem.mem_type != TTM_PL_VRAM) { - if (dev_priv->card_type < NV_50 || !nvbo->tile_flags) + if (dev_priv->card_type < NV_50 || + !nouveau_bo_tile_layout(nvbo)) return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 135594c44167..60a54fae90c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -100,6 +100,9 @@ struct nouveau_bo { int pin_refcnt; }; +#define nouveau_bo_tile_layout(nvbo) \ + ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) + static inline struct nouveau_bo * nouveau_bo(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5c4c929d7f74..9a1fdcf400c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -107,23 +107,29 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) } static bool -nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) { - switch (tile_flags) { - case 0x0000: - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7000: - case 0x7400: - case 0x7a00: - case 0xe000: - break; - default: - NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); - return false; +nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->card_type >= NV_50) { + switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { + case 0x0000: + case 0x1800: + case 0x2800: + case 0x4800: + case 0x7000: + case 0x7400: + case 0x7a00: + case 0xe000: + return true; + } + } else { + if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) + return true; } - return true; + NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); + return false; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index af2bec36d91b..ea3452194cd6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1041,6 +1041,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_PTIMER_TIME: getparam->value = dev_priv->engine.timer.read(dev); break; + case NOUVEAU_GETPARAM_HAS_BO_USAGE: + getparam->value = 1; + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 16380d52cd88..56476d0c6de8 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -546,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, } nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base; - nv_crtc->fb.tile_flags = fb->nvbo->tile_flags; + nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) { ret = RING_SPACE(evo, 2); @@ -578,7 +578,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, fb->nvbo->tile_mode); } if (dev_priv->chipset == 0x50) - OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format); + OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); else OUT_RING(evo, format); diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index 01a714119506..bc5590b1a1ac 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -80,6 +80,7 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 #define NOUVEAU_GETPARAM_PTIMER_TIME 14 +#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15 struct drm_nouveau_getparam { uint64_t param; uint64_t value; @@ -95,6 +96,12 @@ struct drm_nouveau_setparam { #define NOUVEAU_GEM_DOMAIN_GART (1 << 2) #define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) +#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 +#define NOUVEAU_GEM_TILE_16BPP 0x00000001 +#define NOUVEAU_GEM_TILE_32BPP 0x00000002 +#define NOUVEAU_GEM_TILE_ZETA 0x00000004 +#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008 + struct drm_nouveau_gem_info { uint32_t handle; uint32_t domain; -- cgit v1.2.3 From 699ddfd98061b725c52fd34ff1c4346e5b4824d4 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 06:07:32 +0200 Subject: drm/nv10: Balance RTs expected to be accessed simultaneously by the 3d engine. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index f55dd9145b7c..c41e1c200ef5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -143,6 +143,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->no_vm = no_vm; nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; + nvbo->bo.bdev = &dev_priv->ttm.bdev; nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), &align, &size); @@ -177,6 +178,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; } +static void +set_placement_range(struct nouveau_bo *nvbo, uint32_t type) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + + if (dev_priv->card_type == NV_10 && + nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { + /* + * Make sure that the color and depth buffers are handled + * by independent memory controller units. Up to a 9x + * speed up when alpha-blending and depth-test are enabled + * at the same time. + */ + int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; + + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { + nvbo->placement.fpfn = vram_pages / 2; + nvbo->placement.lpfn = ~0; + } else { + nvbo->placement.fpfn = 0; + nvbo->placement.lpfn = vram_pages / 2; + } + } +} + void nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) { @@ -191,6 +217,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) pl->busy_placement = nvbo->busy_placements; set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, type | busy, flags); + + set_placement_range(nvbo, type); } int -- cgit v1.2.3 From 2a56a0b913a8d7314c2c10fdd57d667b599232b4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 1 Oct 2010 14:39:37 +1000 Subject: drm/nva3: fix overflow in fixed point math used for pll calculation And a slight tweak which gets us closer to VBIOS-calculated numbers. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_calc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c index 2cdc2bfe7179..de81151648f8 100644 --- a/drivers/gpu/drm/nouveau/nv50_calc.c +++ b/drivers/gpu/drm/nouveau/nv50_calc.c @@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk, int *N, int *fN, int *M, int *P) { fixed20_12 fb_div, a, b; + u32 refclk = pll->refclk / 10; + u32 max_vco_freq = pll->vco1.maxfreq / 10; + u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10; + clk /= 10; - *P = pll->vco1.maxfreq / clk; + *P = max_vco_freq / clk; if (*P > pll->max_p) *P = pll->max_p; if (*P < pll->min_p) *P = pll->min_p; - /* *M = ceil(refclk / pll->vco.max_inputfreq); */ - a.full = dfixed_const(pll->refclk); - b.full = dfixed_const(pll->vco1.max_inputfreq); + /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */ + a.full = dfixed_const(refclk + max_vco_inputfreq); + b.full = dfixed_const(max_vco_inputfreq); a.full = dfixed_div(a, b); - a.full = dfixed_ceil(a); + a.full = dfixed_floor(a); *M = dfixed_trunc(a); /* fb_div = (vco * *M) / refclk; */ fb_div.full = dfixed_const(clk * *P); fb_div.full = dfixed_mul(fb_div, a); - a.full = dfixed_const(pll->refclk); + a.full = dfixed_const(refclk); fb_div.full = dfixed_div(fb_div, a); /* *N = floor(fb_div); */ -- cgit v1.2.3 From 3c29f9e74591d2f365b159cf59193b19a2f65640 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 15 Oct 2010 22:22:59 +0200 Subject: drm/nouveau: fix nv40 pcie gart size Nouveau sets the PCIE GART size to 64MiB for all cards before nv50, but nv40 has enough RAMIN space to support 512MiB GART size. This patch fixes this value to make use of this hardware capability. Signed-off-by: Lucas Stach Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 288bacac7e5a..15f358404645 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -224,7 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev) int i, ret; if (dev_priv->card_type < NV_50) { - aper_size = (64 * 1024 * 1024); + if(dev_priv->card_type < NV_40) { + aper_size = (64 * 1024 * 1024); + } else { + aper_size = (512 * 1024 * 1024); + } obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ } else { -- cgit v1.2.3 From 5794b5fdb579abf7be2c27c6e0d6106f391a26e4 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 22 Oct 2010 04:39:14 +0200 Subject: drm/nv04: Fix scanout over the 16MB mark. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hw.h | 19 +++++++++++++++++++ drivers/gpu/drm/nouveau/nv04_crtc.c | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.h b/drivers/gpu/drm/nouveau/nouveau_hw.h index 869130f83602..2989090b9434 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.h +++ b/drivers/gpu/drm/nouveau/nouveau_hw.h @@ -415,6 +415,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head) NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos); } +static inline void +nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + NVWriteCRTC(dev, head, NV_PCRTC_START, offset); + + if (dev_priv->card_type == NV_04) { + /* + * Hilarious, the 24th bit doesn't want to stick to + * PCRTC_START... + */ + int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX); + + NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX, + (cre_heb & ~0x40) | ((offset >> 18) & 0x40)); + } +} + static inline void nv_show_cursor(struct drm_device *dev, int head, bool show) { diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index c71abc2a34d5..5b49cec528ee 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -831,7 +831,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, /* Update the framebuffer location. */ regp->fb_start = nv_crtc->fb.offset & ~3; regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8); - NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start); + nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start); /* Update the arbitration parameters. */ nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel, -- cgit v1.2.3 From 01db363979e96115a895f35c823303660f0f328d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 21 Oct 2010 17:43:08 +0200 Subject: drm/nouveau: Use "force" to decide if analog load detection is ok or not. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 69 ++++++++++++----------------- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 -- drivers/gpu/drm/nouveau/nv04_crtc.c | 5 --- 3 files changed, 28 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 6208eedc0970..9ec2b8a81344 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -213,6 +213,24 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } } +static bool +nouveau_connector_poll_allowed(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + bool spare_crtc = false; + + if (dev_priv->card_type >= NV_50) { + return true; + } else { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + spare_crtc |= !crtc->enabled; + + return spare_crtc; + } +} + static enum drm_connector_status nouveau_connector_detect(struct drm_connector *connector, bool force) { @@ -281,7 +299,8 @@ detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); - if (nv_encoder) { + if (nv_encoder && + (force || nouveau_connector_poll_allowed(connector))) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder_helper_funcs *helper = encoder->helper_private; @@ -724,44 +743,6 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } -void -nouveau_connector_set_polling(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - bool spare_crtc = false; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - spare_crtc |= !crtc->enabled; - - connector->polled = 0; - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_TV: - if (dev_priv->card_type >= NV_50 || - (nv_gf4_disp_arch(dev) && spare_crtc)) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_DisplayPort: - case DRM_MODE_CONNECTOR_eDP: - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID || - spare_crtc) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - default: - break; - } -} - static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, @@ -892,6 +873,9 @@ nouveau_connector_create(struct drm_device *dev, int index) case DCB_CONNECTOR_TV_1: case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; + + if (nv_gf4_disp_arch(dev)) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; @@ -903,11 +887,14 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.dithering_mode_property, nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; } - nouveau_connector_set_polling(connector); - drm_sysfs_connector_add(connector); dcb->drm = connector; return dcb->drm; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index c21ed6b16f88..711b1e9203af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector( struct drm_connector * nouveau_connector_create(struct drm_device *, int index); -void -nouveau_connector_set_polling(struct drm_connector *); - int nouveau_connector_bpp(struct drm_connector *); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 5b49cec528ee..40e180741629 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -158,7 +158,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_connector *connector; unsigned char seq1 = 0, crtc17 = 0; unsigned char crtc1A; @@ -213,10 +212,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) NVVgaSeqReset(dev, nv_crtc->index, false); NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A); - - /* Update connector polling modes */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - nouveau_connector_set_polling(connector); } static bool -- cgit v1.2.3 From 06ef3e61dd44f76fef89d8e7ad5d6c845f3f345e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 23 Oct 2010 23:12:37 +0200 Subject: drm/nouveau: Don't poll LVDS outputs. Reported-by: Xavier Chantry Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9ec2b8a81344..1dd52dbfad46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -888,10 +888,12 @@ nouveau_connector_create(struct drm_device *dev, int index) nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (dcb->type != DCB_CONNECTOR_LVDS) { + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } break; } -- cgit v1.2.3 From 56ac7475350ee646f5f7316abcdf65d3be94da1c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Oct 2010 10:26:24 +1000 Subject: drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 5 ++++ drivers/gpu/drm/nouveau/nouveau_mem.c | 14 ++++----- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 8 ++--- drivers/gpu/drm/nouveau/nouveau_state.c | 10 +++++++ drivers/gpu/drm/nouveau/nv50_fifo.c | 5 ++++ drivers/gpu/drm/nouveau/nv50_graph.c | 52 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv50_instmem.c | 1 - 7 files changed, 82 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 60a54fae90c1..10a8d4e78e58 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -307,6 +307,7 @@ struct nouveau_fifo_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); }; struct nouveau_pgraph_object_method { @@ -339,6 +340,7 @@ struct nouveau_pgraph_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, uint32_t size, uint32_t pitch); @@ -1014,6 +1016,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); +extern void nv50_fifo_tlb_flush(struct drm_device *dev); /* nvc0_fifo.c */ extern int nvc0_fifo_init(struct drm_device *); @@ -1091,6 +1094,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); +extern void nv50_graph_tlb_flush(struct drm_device *dev); +extern void nv86_graph_tlb_flush(struct drm_device *dev); /* nvc0_graph.c */ extern int nvc0_graph_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 1165c3e68200..ac3bec024fd5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, } } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); return 0; } @@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) pte++; } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 15f358404645..0b309c1cc3d7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); /* PGRAPH */ - nv50_vm_flush(dev, 0); /* PFIFO */ + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = true; @@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = false; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ea3452194cd6..049f755567e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.load_context = nv50_graph_load_context; engine->graph.unload_context = nv50_graph_unload_context; + if (dev_priv->chipset != 0x86) + engine->graph.tlb_flush = nv50_graph_tlb_flush; + else { + /* from what i can see nvidia do this on every + * pre-NVA3 board except NVAC, but, we've only + * ever seen problems on NV86 + */ + engine->graph.tlb_flush = nv86_graph_tlb_flush; + } engine->fifo.channels = 128; engine->fifo.init = nv50_fifo_init; engine->fifo.takedown = nv50_fifo_takedown; @@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.unload_context = nv50_fifo_unload_context; + engine->fifo.tlb_flush = nv50_fifo_tlb_flush; engine->display.early_init = nv50_display_early_init; engine->display.late_takedown = nv50_display_late_takedown; engine->display.create = nv50_display_create; diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index a46a961102f3..1da65bd60c10 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev) return 0; } +void +nv50_fifo_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 5); +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index cbf5ae2f67d4..8b669d0af610 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ {} }; + +void +nv50_graph_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 0); +} + +void +nv86_graph_tlb_flush(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + bool idle, timeout = false; + unsigned long flags; + u64 start; + u32 tmp; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_mask(dev, 0x400500, 0x00000001, 0x00000000); + + start = ptimer->read(dev); + do { + idle = true; + + for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000)); + + if (timeout) { + NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " + "0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), + nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); + } + + nv50_vm_flush(dev, 0); + + nv_mask(dev, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +} diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a53fc974332b..b773229b7647 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) } dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 4); nv50_vm_flush(dev, 6); gpuobj->im_bound = 1; -- cgit v1.2.3 From 63d6fd32889c46fa40cd1631fb2a0162187311ab Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 25 Oct 2010 02:13:21 +0200 Subject: drm/nv10-nv20: Fix instability after MPLL changes. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_pm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c index 6a6eb697d38e..eb1c70dd82ed 100644 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ b/drivers/gpu/drm/nouveau/nv04_pm.c @@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) reg += 4; nouveau_hw_setpll(dev, reg, &state->calc); + + if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) { + if (dev_priv->card_type == NV_20) + nv_mask(dev, 0x1002c4, 0, 1 << 20); + + /* Reset the DLLs */ + nv_mask(dev, 0x1002c0, 0, 1 << 8); + } + kfree(state); } -- cgit v1.2.3 From 84b8081c2baf84b52ac9bf79f07edcea975ab0b5 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 26 Oct 2010 02:17:56 +0200 Subject: drm/nouveau: Don't use load detection for connector polling. Analog output polling makes GL programs jerky when pageflip is being used because it's carried out with the mode_config mutex held. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1dd52dbfad46..52c356e9a3d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -213,24 +213,6 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } } -static bool -nouveau_connector_poll_allowed(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - bool spare_crtc = false; - - if (dev_priv->card_type >= NV_50) { - return true; - } else { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - spare_crtc |= !crtc->enabled; - - return spare_crtc; - } -} - static enum drm_connector_status nouveau_connector_detect(struct drm_connector *connector, bool force) { @@ -299,8 +281,7 @@ detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); - if (nv_encoder && - (force || nouveau_connector_poll_allowed(connector))) { + if (nv_encoder && force) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder_helper_funcs *helper = encoder->helper_private; @@ -868,14 +849,12 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.scaling_mode_property, nv_connector->scaling_mode); } + connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* fall-through */ case DCB_CONNECTOR_TV_0: case DCB_CONNECTOR_TV_1: case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; - - if (nv_gf4_disp_arch(dev)) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; -- cgit v1.2.3 From b54262f3c828ee17e27632d0d60255281c02e1a5 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Tue, 26 Oct 2010 12:48:28 +0200 Subject: drm/nouveau: Fix compilation issues in nouveau_pm when CONFIG_HWMON is not set Signed-off-by: Martin Peres Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 1c99c55d6d46..9f7b158f5825 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -284,6 +284,7 @@ nouveau_sysfs_fini(struct drm_device *dev) } } +#ifdef CONFIG_HWMON static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { @@ -395,10 +396,12 @@ static struct attribute *hwmon_attributes[] = { static const struct attribute_group hwmon_attrgroup = { .attrs = hwmon_attributes, }; +#endif static int nouveau_hwmon_init(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct device *hwmon_dev; @@ -425,13 +428,14 @@ nouveau_hwmon_init(struct drm_device *dev) } pm->hwmon = hwmon_dev; - +#endif return 0; } static void nouveau_hwmon_fini(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; @@ -439,6 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev) sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); hwmon_device_unregister(pm->hwmon); } +#endif } int -- cgit v1.2.3 From dd661e5f4e87609e7a9b4cbdff305dca7f494e7b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 1 Nov 2010 18:06:28 +0100 Subject: drm/nouveau: Return error from nouveau_gpuobj_new if we're out of RAMIN. Reported-by: Tomas Miljenovic Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 896cf8634144..dd572adca02a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -129,7 +129,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (ramin == NULL) { spin_unlock(&dev_priv->ramin_lock); nouveau_gpuobj_ref(NULL, &gpuobj); - return ret; + return -ENOMEM; } ramin = drm_mm_get_block_atomic(ramin, size, align); -- cgit v1.2.3 From 9d5a6c4353eeac1e0095e731a0a746254f23af83 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 1 Nov 2010 18:08:26 +0100 Subject: drm/nouveau: Make PCIE GART size depend on the available RAMIN space. Reported-by: Tomas Miljenovic Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 0b309c1cc3d7..d4ac97007038 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -224,11 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev) int i, ret; if (dev_priv->card_type < NV_50) { - if(dev_priv->card_type < NV_40) { - aper_size = (64 * 1024 * 1024); - } else { - aper_size = (512 * 1024 * 1024); - } + if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024) + aper_size = 64 * 1024 * 1024; + else + aper_size = 512 * 1024 * 1024; + obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ } else { -- cgit v1.2.3 From cac8f05b4294d18cfa940511c286ca03aa6590ad Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Wed, 20 Oct 2010 01:09:56 +0200 Subject: drm/nouveau/pm: improve memtiming mappings Improvements: - Fix bug in switch statement - Add parts of 0x10022c, 0x10023c - Clean up 0x100234 - Comment out assumption in 0x100228 until verified Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index ac3bec024fd5..fe4a30dc4b42 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -651,6 +651,7 @@ nouveau_mem_gart_init(struct drm_device *dev) void nouveau_mem_timing_init(struct drm_device *dev) { + /* cards < NVC0 only */ struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_memtimings *memtimings = &pm->memtimings; @@ -717,14 +718,14 @@ nouveau_mem_timing_init(struct drm_device *dev) tUNK_19 = 1; tUNK_20 = 0; tUNK_21 = 0; - switch (min(recordlen, 21)) { - case 21: + switch (min(recordlen, 22)) { + case 22: tUNK_21 = entry[21]; - case 20: + case 21: tUNK_20 = entry[20]; - case 19: + case 20: tUNK_19 = entry[19]; - case 18: + case 19: tUNK_18 = entry[18]; default: tUNK_0 = entry[0]; @@ -754,24 +755,30 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); if(recordlen > 19) { timing->reg_100228 += (tUNK_19 - 1) << 24; - } else { + }/* I cannot back-up this else-statement right now + else { timing->reg_100228 += tUNK_12 << 24; - } + }*/ /* XXX: reg_10022c */ + timing->reg_10022c = tUNK_2 - 1; timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | tUNK_13 << 8 | tUNK_13); /* XXX: +6? */ timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC); - if(tUNK_10 > tUNK_11) { - timing->reg_100234 += tUNK_10 << 16; - } else { - timing->reg_100234 += tUNK_11 << 16; + timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; + + /* XXX; reg_100238, reg_10023c + * reg: 0x00?????? + * reg_10023c: + * 0 for pre-NV50 cards + * 0x????0202 for NV50+ cards (empirical evidence) */ + if(dev_priv->card_type >= NV_50) { + timing->reg_10023c = 0x202; } - /* XXX; reg_100238, reg_10023c */ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, timing->reg_100220, timing->reg_100224, timing->reg_100228, timing->reg_10022c); -- cgit v1.2.3 From 5bead799d3f8f1500c4b59301b8a2732a92f559f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 4 Nov 2010 09:56:12 +1000 Subject: drm/nouveau: don't expose backlight control when available through ACPI Avoid confusing userspace by not publishing backlight controls if ACPI equivalents are available. Reported-by: Aaron Sowry Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 406228f4a2a0..b14c81110575 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -31,6 +31,7 @@ */ #include +#include #include "drmP.h" #include "nouveau_drv.h" @@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; +#ifdef CONFIG_ACPI + if (acpi_video_backlight_support()) { + NV_INFO(dev, "ACPI backlight interface available, " + "not registering our own\n"); + return 0; + } +#endif + switch (dev_priv->card_type) { case NV_40: return nouveau_nv40_backlight_init(dev); -- cgit v1.2.3 From c1b60ece91460214b5135360a375f3f6fbb59608 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 11 Nov 2010 00:56:37 +0100 Subject: drm/nouveau: Fix a few confusions between "chipset" and "card_type". Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- drivers/gpu/drm/nouveau/nouveau_i2c.c | 2 +- drivers/gpu/drm/nouveau/nouveau_temp.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 5f21030a293b..b2293576f278 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6829,7 +6829,7 @@ nouveau_bios_posted(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; unsigned htotal; - if (dev_priv->chipset >= NV_50) { + if (dev_priv->card_type >= NV_50) { if (NVReadVgaCrtc(dev, 0, 0x00) == 0 && NVReadVgaCrtc(dev, 0, 0x1a) == 0) return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index fdd7e3de79c8..cb389d014326 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index) if (index >= DCB_MAX_NUM_I2C_ENTRIES) return NULL; - if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) { + if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) { uint32_t reg = 0xe500, val; if (i2c->port_type == 6) { diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 16bbbf1eff63..7ecc4adc1e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev) int offset = sensor->offset_mult / sensor->offset_div; int core_temp; - if (dev_priv->chipset >= 0x50) { + if (dev_priv->card_type >= NV_50) { core_temp = nv_rd32(dev, 0x20008); } else { core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff; -- cgit v1.2.3 From ab838338a2a9e0cb8346eb0cab9977be13e8dce5 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 16 Nov 2010 18:40:52 -0500 Subject: nouveau: Acknowledge HPD irq in handler, not bottom half The old code generated an interrupt storm bad enough to completely take down my system. Signed-off-by: Andy Lutomirski Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 6 ++++++ drivers/gpu/drm/nouveau/nouveau_irq.c | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 35 +++++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 10a8d4e78e58..1c7db64c03bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -584,6 +584,12 @@ struct drm_nouveau_private { struct work_struct irq_work; struct work_struct hpd_work; + struct { + spinlock_t lock; + uint32_t hpd0_bits; + uint32_t hpd1_bits; + } hpd_state; + struct list_head vbl_waiting; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index e2f2d59be3ea..7bfd9e6c9d67 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -60,6 +60,7 @@ nouveau_irq_preinstall(struct drm_device *dev) if (dev_priv->card_type >= NV_50) { INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); + spin_lock_init(&dev_priv->hpd_state.lock); INIT_LIST_HEAD(&dev_priv->vbl_waiting); } } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 55c9663ef2bf..f624c611ddea 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) struct drm_connector *connector; const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; uint32_t unplug_mask, plug_mask, change_mask; - uint32_t hpd0, hpd1 = 0; + uint32_t hpd0, hpd1; - hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); + spin_lock_irq(&dev_priv->hpd_state.lock); + hpd0 = dev_priv->hpd_state.hpd0_bits; + dev_priv->hpd_state.hpd0_bits = 0; + hpd1 = dev_priv->hpd_state.hpd1_bits; + dev_priv->hpd_state.hpd1_bits = 0; + spin_unlock_irq(&dev_priv->hpd_state.lock); + + hpd0 &= nv_rd32(dev, 0xe050); if (dev_priv->chipset >= 0x90) - hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); + hpd1 &= nv_rd32(dev, 0xe070); plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); @@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); } - nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); - if (dev_priv->chipset >= 0x90) - nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); - drm_helper_hpd_irq_event(dev); } @@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev) uint32_t delayed = 0; if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { - if (!work_pending(&dev_priv->hpd_work)) - queue_work(dev_priv->wq, &dev_priv->hpd_work); + uint32_t hpd0_bits, hpd1_bits = 0; + + hpd0_bits = nv_rd32(dev, 0xe054); + nv_wr32(dev, 0xe054, hpd0_bits); + + if (dev_priv->chipset >= 0x90) { + hpd1_bits = nv_rd32(dev, 0xe074); + nv_wr32(dev, 0xe074, hpd1_bits); + } + + spin_lock(&dev_priv->hpd_state.lock); + dev_priv->hpd_state.hpd0_bits |= hpd0_bits; + dev_priv->hpd_state.hpd1_bits |= hpd1_bits; + spin_unlock(&dev_priv->hpd_state.lock); + + queue_work(dev_priv->wq, &dev_priv->hpd_work); } while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { -- cgit v1.2.3 From 16790569eddf4d406a16a65f4750f405fa669c52 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 14 Nov 2010 20:24:35 -0500 Subject: drm/radeon/kms: fix and unify tiled buffer alignment checking for r6xx/7xx Tiled buffers have the same alignment requirements regardless of whether the surface is for db, cb, or textures. Previously, the calculations where inconsistent for each buffer type. - Unify the alignment calculations in a common function - Standardize the alignment units (pixels for pitch/height/depth, bytes for base) - properly check the buffer base alignments Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 309 ++++++++++++++++++++++++--------------- drivers/gpu/drm/radeon/r600d.h | 6 + 2 files changed, 199 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 37cc2aa9f923..0f90fc3482ce 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -50,6 +50,7 @@ struct r600_cs_track { u32 nsamples; u32 cb_color_base_last[8]; struct radeon_bo *cb_color_bo[8]; + u64 cb_color_bo_mc[8]; u32 cb_color_bo_offset[8]; struct radeon_bo *cb_color_frag_bo[8]; struct radeon_bo *cb_color_tile_bo[8]; @@ -67,6 +68,7 @@ struct r600_cs_track { u32 db_depth_size; u32 db_offset; struct radeon_bo *db_bo; + u64 db_bo_mc; }; static inline int r600_bpe_from_format(u32 *bpe, u32 format) @@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format) return 0; } +struct array_mode_checker { + int array_mode; + u32 group_size; + u32 nbanks; + u32 npipes; + u32 nsamples; + u32 bpe; +}; + +/* returns alignment in pixels for pitch/height/depth and bytes for base */ +static inline int r600_get_array_mode_alignment(struct array_mode_checker *values, + u32 *pitch_align, + u32 *height_align, + u32 *depth_align, + u64 *base_align) +{ + u32 tile_width = 8; + u32 tile_height = 8; + u32 macro_tile_width = values->nbanks; + u32 macro_tile_height = values->npipes; + u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples; + u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes; + + switch (values->array_mode) { + case ARRAY_LINEAR_GENERAL: + /* technically tile_width/_height for pitch/height */ + *pitch_align = 1; /* tile_width */ + *height_align = 1; /* tile_height */ + *depth_align = 1; + *base_align = 1; + break; + case ARRAY_LINEAR_ALIGNED: + *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe)); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_1D_TILED_THIN1: + *pitch_align = max((u32)tile_width, + (u32)(values->group_size / + (tile_height * values->bpe * values->nsamples))); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_2D_TILED_THIN1: + *pitch_align = max((u32)macro_tile_width, + (u32)(((values->group_size / tile_height) / + (values->bpe * values->nsamples)) * + values->nbanks)) * tile_width; + *height_align = macro_tile_height * tile_height; + *depth_align = 1; + *base_align = max(macro_tile_bytes, + (*pitch_align) * values->bpe * (*height_align) * values->nsamples); + break; + default: + return -EINVAL; + } + + return 0; +} + static void r600_cs_track_init(struct r600_cs_track *track) { int i; @@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track) track->cb_color_info[i] = 0; track->cb_color_bo[i] = NULL; track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_bo_mc[i] = 0xFFFFFFFF; } track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->db_bo = NULL; + track->db_bo_mc = 0xFFFFFFFF; /* assume the biggest format and that htile is enabled */ track->db_depth_info = 7 | (1 << 25); track->db_depth_view = 0xFFFFC000; @@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track) static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) { struct r600_cs_track *track = p->track; - u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align; + u32 bpe = 0, slice_tile_max, size, tmp; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; volatile u32 *ib = p->ib->ptr; unsigned array_mode; @@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) i, track->cb_color_info[i]); return -EINVAL; } - /* pitch is the number of 8x8 tiles per row */ - pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1; + /* pitch in pixels */ + pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8; slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]); + + base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i]; + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, + G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, + track->cb_color_info[i]); + return -EINVAL; + } switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: - /* technically height & 0x7 */ break; case V_0280A0_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* avoid breaking userspace */ if (height > 7) height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, @@ -244,8 +293,24 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) track->cb_color_info[i]); return -EINVAL; } + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + /* check offset */ - tmp = height * pitch * 8 * bpe; + tmp = height * pitch * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ @@ -260,15 +325,11 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) return -EINVAL; } } - if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]); - return -EINVAL; - } /* limit max tile */ - tmp = (height * pitch * 8) >> 6; + tmp = (height * pitch) >> 6; if (tmp < slice_tile_max) slice_tile_max = tmp; - tmp = S_028060_PITCH_TILE_MAX(pitch - 1) | + tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) | S_028060_SLICE_TILE_MAX(slice_tile_max - 1); ib[track->cb_color_size_idx[i]] = tmp; return 0; @@ -310,7 +371,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) /* Check depth buffer */ if (G_028800_STENCIL_ENABLE(track->db_depth_control) || G_028800_Z_ENABLE(track->db_depth_control)) { - u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max; + u32 nviews, bpe, ntiles, size, slice_tile_max; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; + int array_mode; + if (track->db_bo == NULL) { dev_warn(p->dev, "z/stencil with no depth buffer\n"); return -EINVAL; @@ -353,41 +419,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); } else { size = radeon_bo_size(track->db_bo); - pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1; + /* pitch in pixels */ + pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8; slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; - switch (G_028010_ARRAY_MODE(track->db_depth_info)) { + base_offset = track->db_bo_mc + track->db_offset; + array_mode = G_028010_ARRAY_MODE(track->db_depth_info); + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_028010_ARRAY_MODE(track->db_depth_info), + track->db_depth_info); + return -EINVAL; + } + switch (array_mode) { case V_028010_ARRAY_1D_TILED_THIN1: - pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8); - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* don't break userspace */ height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_028010_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, @@ -395,15 +454,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) track->db_depth_info); return -EINVAL; } - if (!IS_ALIGNED(track->db_offset, track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset); + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { - dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n", + dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n", track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, radeon_bo_size(track->db_bo)); return -EINVAL; @@ -954,6 +1025,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->cb_color_base_last[tmp] = ib[idx]; track->cb_color_bo[tmp] = reloc->robj; + track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset; break; case DB_DEPTH_BASE: r = r600_cs_packet_next_reloc(p, &reloc); @@ -965,6 +1037,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx track->db_offset = radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->db_bo = reloc->robj; + track->db_bo_mc = reloc->lobj.gpu_offset; break; case DB_HTILE_DATA_BASE: case SQ_PGM_START_FS: @@ -1086,16 +1159,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, struct radeon_bo *texture, struct radeon_bo *mipmap, + u64 base_offset, + u64 mip_offset, u32 tiling_flags) { struct r600_cs_track *track = p->track; u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0; - u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align; + u32 word0, word1, l0_size, mipmap_size; + u32 height_align, pitch, pitch_align, depth_align; + u64 base_align; + struct array_mode_checker array_check; /* on legacy kernel we don't perform advanced check */ if (p->rdev == NULL) return 0; + /* convert to bytes */ + base_offset <<= 8; + mip_offset <<= 8; + word0 = radeon_get_ib_value(p, idx + 0); if (tiling_flags & RADEON_TILING_MACRO) word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); @@ -1128,46 +1210,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i return -EINVAL; } - pitch = G_038000_PITCH(word0) + 1; - switch (G_038000_TILE_MODE(word0)) { - case V_038000_ARRAY_LINEAR_GENERAL: - pitch_align = 1; - /* XXX check height align */ - break; - case V_038000_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - default: - dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, - G_038000_TILE_MODE(word0), word0); + /* pitch in texels */ + pitch = (G_038000_PITCH(word0) + 1) * 8; + array_check.array_mode = G_038000_TILE_MODE(word0); + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = 1; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", + __func__, __LINE__, G_038000_TILE_MODE(word0)); + return -EINVAL; + } + + /* XXX check height as well... */ + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n", + __func__, __LINE__, base_offset); + return -EINVAL; + } + if (!IS_ALIGNED(mip_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n", + __func__, __LINE__, mip_offset); return -EINVAL; } - /* XXX check offset align */ word0 = radeon_get_ib_value(p, idx + 4); word1 = radeon_get_ib_value(p, idx + 5); @@ -1402,7 +1476,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p, mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); mipmap = reloc->robj; r = r600_check_texture_resource(p, idx+(i*7)+1, - texture, mipmap, reloc->lobj.tiling_flags); + texture, mipmap, + base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2), + mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3), + reloc->lobj.tiling_flags); if (r) return r; ib[idx+1+(i*7)+2] += base_offset; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 966a793e225b..bff4dc4f410f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -51,6 +51,12 @@ #define PTE_READABLE (1 << 5) #define PTE_WRITEABLE (1 << 6) +/* tiling bits */ +#define ARRAY_LINEAR_GENERAL 0x00000000 +#define ARRAY_LINEAR_ALIGNED 0x00000001 +#define ARRAY_1D_TILED_THIN1 0x00000002 +#define ARRAY_2D_TILED_THIN1 0x00000004 + /* Registers */ #define ARB_POP 0x2418 #define ENABLE_TC128 (1 << 30) -- cgit v1.2.3 From 21e2eae4daaecf2f2a391e4f4b596c800f198edf Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 14 Nov 2010 23:08:27 +0300 Subject: drm: radeon: fix error value sign enable_vblank implementations should use negative result to indicate error. radeon_enable_vblank() returns EINVAL in this case. Change this to -EINVAL. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 2f349a300195..465746bd51b7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } else { switch (crtc) { @@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } -- cgit v1.2.3 From d33ef52d9db8a36900dd53f2e32db9a521ace259 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 16:53:14 -0500 Subject: drm/radeon/kms: fix typo in r600 cs checker Looks like a typo in: drm/radeon/r600: fix tiling issues in CS checker. (f30df2fad0c901e74ac9a52a488a54c69a373a41) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0f90fc3482ce..9bebac1ec006 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -315,7 +315,7 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ /* it rounds up height too far for slice tile max but the BO is smaller */ - tmp = (height - 7) * 8 * bpe; + tmp = (height - 7) * pitch * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); return -EINVAL; -- cgit v1.2.3 From ba251bde9ab8bdce8fbd3f60dbb71b36cc4c9adf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:39 -0500 Subject: drm/radeon/kms: turn the backlight off explicitly for dpms Seems some newer systems require this explicitly. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index f678257c42e6..d55cb58283a9 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1086,6 +1086,8 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON); } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -1095,20 +1097,31 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); break; } } else { switch (mode) { case DRM_MODE_DPMS_ON: args.ucAction = ATOM_ENABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: args.ucAction = ATOM_DISABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); -- cgit v1.2.3 From c7a71fc761551dc8be8543f14a90d08cda4e77f9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 02:49:40 -0500 Subject: drm/radeon/kms/atom: set sane defaults in atombios_get_encoder_mode() If there was no connector mapped to the encoder, atombios_get_encoder_mode() returned 0 which is the id for DP. Return something sane instead based on the encoder id. This avoids hitting the DP paths on non-DP encoders. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index d55cb58283a9..c6981dfd9156 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -595,6 +595,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(struct drm_encoder *encoder) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; @@ -602,9 +603,20 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) struct radeon_connector_atom_dig *dig_connector; connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return 0; - + if (!connector) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + return ATOM_ENCODER_MODE_DVI; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + default: + return ATOM_ENCODER_MODE_CRT; + } + } radeon_connector = to_radeon_connector(connector); switch (connector->connector_type) { -- cgit v1.2.3 From 8b834852d705af75ba942b040ca28533329ff13c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 02:54:42 -0500 Subject: drm/radeon/kms: properly power up/down the eDP panel as needed (v4) The eDP panel must be powered up for aux transactions, so power it up for detect and mode probe functions, otherwise power it up or down based on dpms. v2: - only mess with eDP panel on DCE4+ - only mess with eDP panel on eDP connectors, not all DP connectors v3: - be extra careful to only mess with eDP panels on eDP connectors v4: - avoid possible null derefernce if a connector has not been assigned to the encoder Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 18 +++++++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 50 ++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 2 ++ 3 files changed, 70 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index fe6c74780f18..3bef9f6d66fd 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1008,9 +1008,21 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector) static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; int ret; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + } ret = radeon_ddc_get_modes(radeon_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + } + return ret; } @@ -1029,8 +1041,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP is always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); } else { radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c6981dfd9156..63f4964e8d2d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -990,6 +990,36 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +void +atombios_set_edp_panel_power(struct drm_connector *connector, int action) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + union dig_transmitter_control args; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + uint8_t frev, crev; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) + return; + + if (!ASIC_IS_DCE4(rdev)) + return; + + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) || + (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) + return; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + memset(&args, 0, sizeof(args)); + + args.v1.ucAction = action; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1094,6 +1124,15 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + radeon_dig_connector->edp_on = true; + } dp_link_train(encoder, connector); if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON); @@ -1106,8 +1145,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_OFF: atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + radeon_dig_connector->edp_on = false; + } } if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 680f57644e86..ef588835201f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -385,6 +385,7 @@ struct radeon_connector_atom_dig { u8 dp_sink_type; int dp_clock; int dp_lane_count; + bool edp_on; }; struct radeon_gpio_rec { @@ -526,6 +527,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); extern void atombios_digital_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); +extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action); extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); -- cgit v1.2.3 From 99999aaa091bdb3e16b5eed22f3a9a567f84f0fe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:41 -0500 Subject: drm/radeon/kms/atom: cleanup and unify DVO handling Handle all the various asic family specific things for DVO. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_encoders.c | 90 +++++++++++++------------ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 73f600d39ad4..3a7095743d44 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1262,6 +1262,10 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); (rdev->family == CHIP_RS400) || \ (rdev->family == CHIP_RS480)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) +#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \ + (rdev->family == CHIP_RS690) || \ + (rdev->family == CHIP_RS740) || \ + (rdev->family >= CHIP_R600)) #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 63f4964e8d2d..07df990a897b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -176,6 +176,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) return false; } } + void radeon_link_encoder_connector(struct drm_device *dev) { @@ -426,52 +427,49 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) } -void -atombios_external_tmds_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; - int index = 0; - - memset(&args, 0, sizeof(args)); - - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - - args.sXTmdsEncoder.ucEnable = action; - - if (radeon_encoder->pixel_clock > 165000) - args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; - - /*if (pScrn->rgbBits == 8)*/ - args.sXTmdsEncoder.ucMisc |= (1 << 1); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} +union dvo_encoder_control { + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; +}; -static void -atombios_ddia_setup(struct drm_encoder *encoder, int action) +void +atombios_dvo_setup(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DVO_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; + union dvo_encoder_control args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); memset(&args, 0, sizeof(args)); - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + if (ASIC_IS_DCE3(rdev)) { + /* DCE3+ */ + args.dvo_v3.ucAction = action; + args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.dvo_v3.ucDVOConfig = 0; /* XXX */ + } else if (ASIC_IS_DCE2(rdev)) { + /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */ + args.dvo.sDVOEncoder.ucAction = action; + args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + /* DFP1, CRT1, TV1 depending on the type of port */ + args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + + if (radeon_encoder->pixel_clock > 165000) + args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; + } else { + /* R4xx, R5xx */ + args.ext_tmds.sXTmdsEncoder.ucEnable = action; - args.sDVOEncoder.ucAction = action; - args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->pixel_clock > 165000) + args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (radeon_encoder->pixel_clock > 165000) - args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8)*/ + args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; + } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } union lvds_encoder_control { @@ -532,14 +530,14 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } else { if (dig->linkb) args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; /*if (pScrn->rgbBits == 8) */ - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } break; case 2: @@ -846,6 +844,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t memset(&args, 0, sizeof(args)); switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: @@ -1085,9 +1086,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + if (ASIC_IS_DCE3(rdev)) + is_dig = true; + else + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_LVDS: index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); break; @@ -1317,7 +1323,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) break; default: DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - break; + return; } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -1475,11 +1481,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_ENABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: @@ -1670,11 +1674,9 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_DISABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_DISABLE); + atombios_dvo_setup(encoder, ATOM_DISABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 0b8397000f4c..59f834ba283d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -670,7 +670,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, if (rdev->is_atom_bios) { radeon_encoder->pixel_clock = adjusted_mode->clock; - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); } else { fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ef588835201f..663bc51cf99e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -524,7 +524,7 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); -extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); +extern void atombios_dvo_setup(struct drm_encoder *encoder, int action); extern void atombios_digital_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action); -- cgit v1.2.3 From 3e4b99828d1c8abefefd37474503605c811c1b51 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:42 -0500 Subject: drm/radeon/kms/atom: add proper external encoders support These are external encoder chips connected via DVO or DP. The actual external encoder programming is handled by the kms encoder functions for primary encoder. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 183 +++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 184 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 07df990a897b..041943df966b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -229,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } +struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + if (radeon_encoder->is_ext_encoder) + return NULL; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + if (other_encoder == encoder) + continue; + other_radeon_encoder = to_radeon_encoder(other_encoder); + if (other_radeon_encoder->is_ext_encoder && + (radeon_encoder->devices & other_radeon_encoder->devices)) + return other_encoder; + } + return NULL; +} + void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -1021,6 +1042,75 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +union external_encoder_control { + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; +}; + +static void +atombios_external_encoder_setup(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union external_encoder_control args; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + u8 frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + } + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + /* no params on frev 1 */ + break; + case 2: + switch (crev) { + case 1: + case 2: + args.v1.sDigEncoder.ucAction = action; + args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_clock == 270000) + args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.v1.sDigEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v1.sDigEncoder.ucLaneNum = 8; + else + args.v1.sDigEncoder.ucLaneNum = 4; + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1064,6 +1154,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index = 0; bool is_dig = false; @@ -1191,6 +1282,24 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; } } + + if (ext_encoder) { + int action; + + switch (mode) { + case DRM_MODE_DPMS_ON: + default: + action = ATOM_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + action = ATOM_DISABLE; + break; + } + atombios_external_encoder_setup(encoder, ext_encoder, action); + } + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } @@ -1438,6 +1547,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -1498,6 +1608,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; } + + if (ext_encoder) { + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + } + atombios_apply_encoder_quirks(encoder, adjusted_mode); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -1698,6 +1813,53 @@ disable_done: radeon_encoder->active_device = 0; } +/* these are handled by the primary encoders */ +static void radeon_atom_ext_prepare(struct drm_encoder *encoder) +{ + +} + +static void radeon_atom_ext_commit(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_atom_ext_disable(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) +{ + +} + +static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { + .dpms = radeon_atom_ext_dpms, + .mode_fixup = radeon_atom_ext_mode_fixup, + .prepare = radeon_atom_ext_prepare, + .mode_set = radeon_atom_ext_mode_set, + .commit = radeon_atom_ext_commit, + .disable = radeon_atom_ext_disable, + /* no detect for TMDS/LVDS yet */ +}; + static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { .dpms = radeon_atom_encoder_dpms, .mode_fixup = radeon_atom_mode_fixup, @@ -1807,6 +1969,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; + radeon_encoder->is_ext_encoder = false; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: @@ -1848,6 +2011,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->rmx_type = RMX_FULL; drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); } else { drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); @@ -1856,5 +2022,22 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t } drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; + case ENCODER_OBJECT_ID_SI170B: + case ENCODER_OBJECT_ID_CH7303: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: + case ENCODER_OBJECT_ID_TITFP513: + case ENCODER_OBJECT_ID_VT1623: + case ENCODER_OBJECT_ID_HDMI_SI1930: + /* these are handled by the primary encoders */ + radeon_encoder->is_ext_encoder = true; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + else + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); + break; } } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 663bc51cf99e..e301c6f9e059 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -375,6 +375,7 @@ struct radeon_encoder { int hdmi_config_offset; int hdmi_audio_workaround; int hdmi_buffer_status; + bool is_ext_encoder; }; struct radeon_connector_atom_dig { -- cgit v1.2.3 From a5193fe50e7f21c26d22c17c8196420fac1a3ca7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 17:56:49 -0500 Subject: drm/radeon/kms: register an i2c adapter name for the dp aux bus This causes the connector to not be added since i2c init fails for the adapter. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=31688 Noticed by Ari Savolainen. Signed-off-by: Alex Deucher Cc: Ari Savolainen Cc: Jean Delvare Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 0cfbba02c4d0..d263bd1a0d80 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -946,6 +946,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; + sprintf(i2c->adapter.name, "Radeon aux bus %s", name); i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.algo_data = &i2c->algo.dp; i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; -- cgit v1.2.3 From 2f5993cca67f9c80dcd390feef13695ca072b8a5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 13:24:48 +0100 Subject: drm/vmwgfx: Fix up an error path during bo creation Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 36e129f0023f..5408b1b7996f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -862,7 +862,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) - return ret; + goto out_no_dmabuf; tmp = ttm_bo_reference(&vmw_user_bo->dma.base); ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile, @@ -870,19 +870,21 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, false, ttm_buffer_type, &vmw_user_dmabuf_release, NULL); - if (unlikely(ret != 0)) { - ttm_bo_unref(&tmp); - } else { + if (unlikely(ret != 0)) + goto out_no_base_object; + else { rep->handle = vmw_user_bo->base.hash.key; rep->map_handle = vmw_user_bo->dma.base.addr_space_offset; rep->cur_gmr_id = vmw_user_bo->base.hash.key; rep->cur_gmr_offset = 0; } - ttm_bo_unref(&tmp); +out_no_base_object: + ttm_bo_unref(&tmp); +out_no_dmabuf: ttm_read_unlock(&vmaster->lock); - return 0; + return ret; } int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From 268b2510de14f62134d87ba9b4981816192db386 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 19:00:26 -0500 Subject: drm/radeon/kms: fix alignment when allocating buffers We were previously dropping alignment requests on the floor when allocating buffers so we always ended up page aligned. Certain tiling modes on 6xx+ require larger alignment which wasn't happening before. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_blit_kms.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/r600_blit_kms.c | 2 +- drivers/gpu/drm/radeon/radeon_benchmark.c | 4 ++-- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_gart.c | 4 ++-- drivers/gpu/drm/radeon/radeon_gem.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 7 ++++--- drivers/gpu/drm/radeon/radeon_object.h | 7 ++++--- drivers/gpu/drm/radeon/radeon_ring.c | 6 +++--- drivers/gpu/drm/radeon/radeon_test.c | 4 ++-- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- drivers/gpu/drm/radeon/rv770.c | 4 ++-- 13 files changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index ac3b6dde23db..e0e590110dd4 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -459,7 +459,7 @@ int evergreen_blit_init(struct radeon_device *rdev) obj_size += evergreen_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("evergreen failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0f806cc7dc75..a3552594ccc4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2718,7 +2718,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev) /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size, - true, + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->ih.ring_obj); if (r) { diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 8362974ef41a..86e5aa07f0db 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -501,7 +501,7 @@ int r600_blit_init(struct radeon_device *rdev) obj_size += r6xx_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("r600 failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 7932dc4d6b90..c558685cc637 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -41,7 +41,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, size = bsize; n = 1024; - r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj); if (r) { goto out_cleanup; } @@ -53,7 +53,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8adfedfe547f..d8ac1849180d 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -180,7 +180,7 @@ int radeon_wb_init(struct radeon_device *rdev) int r; if (rdev->wb.wb_obj == NULL) { - r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true, + r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj); if (r) { dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index e65b90317fab..65016117d95f 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -79,8 +79,8 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) if (rdev->gart.table.vram.robj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->gart.table_size, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->gart.table.vram.robj); if (r) { return r; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index d1e595d91723..df95eb83dac6 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size, if (alignment < PAGE_SIZE) { alignment = PAGE_SIZE; } - r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj); + r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj); if (r) { if (r != -ERESTARTSYS) DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n", diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8eb183466015..1d067743fee0 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -86,11 +86,12 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) } int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, - unsigned long size, bool kernel, u32 domain, - struct radeon_bo **bo_ptr) + unsigned long size, int byte_align, bool kernel, u32 domain, + struct radeon_bo **bo_ptr) { struct radeon_bo *bo; enum ttm_bo_type type; + int page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; int r; if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { @@ -115,7 +116,7 @@ retry: /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, 0, 0, !kernel, NULL, size, + &bo->placement, page_align, 0, !kernel, NULL, size, &radeon_ttm_bo_destroy); mutex_unlock(&rdev->vram_mutex); if (unlikely(r != 0)) { diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 3481bc7f6f58..d143702b244a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -137,9 +137,10 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, } extern int radeon_bo_create(struct radeon_device *rdev, - struct drm_gem_object *gobj, unsigned long size, - bool kernel, u32 domain, - struct radeon_bo **bo_ptr); + struct drm_gem_object *gobj, unsigned long size, + int byte_align, + bool kernel, u32 domain, + struct radeon_bo **bo_ptr); extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 6ea798ce8218..06e79822a2bf 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -176,8 +176,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev) INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib); /* Allocate 1M object buffer */ r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, - true, RADEON_GEM_DOMAIN_GTT, - &rdev->ib_pool.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, + &rdev->ib_pool.robj); if (r) { DRM_ERROR("radeon: failed to ib pool (%d).\n", r); return r; @@ -332,7 +332,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.ring_size = ring_size; /* Allocate ring buffer */ if (rdev->cp.ring_obj == NULL) { - r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true, + r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->cp.ring_obj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 313c96bc09da..5b44f652145c 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -52,7 +52,7 @@ void radeon_test_moves(struct radeon_device *rdev) goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); @@ -71,7 +71,7 @@ void radeon_test_moves(struct radeon_device *rdev) void **gtt_start, **gtt_end; void **vram_start, **vram_end; - r = radeon_bo_create(rdev, NULL, size, true, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 01c2c736a1da..1272e4b6a1d4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -529,7 +529,7 @@ int radeon_ttm_init(struct radeon_device *rdev) DRM_ERROR("Failed initializing VRAM heap.\n"); return r; } - r = radeon_bo_create(rdev, NULL, 256 * 1024, true, + r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->stollen_vga_memory); if (r) { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 245374e2b778..4dfead8cee33 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -915,8 +915,8 @@ static int rv770_vram_scratch_init(struct radeon_device *rdev) if (rdev->vram_scratch.robj == NULL) { r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->vram_scratch.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); if (r) { return r; } -- cgit v1.2.3 From 1aa52bd3bc839064d5a3e4de406850f4a3aa5378 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 12:11:03 -0500 Subject: drm/radeon/kms: fix tiling info on evergreen We aren't currently using tiling in userspace on evergreen, but the info we currently return for the tiling info query (gb_addr_config) is no adequate for userspace tiling alignment calculations. It does not contain the bank info. Create a custom tiling info dword with all the necessary info (num channels, num banks, group size, row size). Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 488c36c8f5e6..4dc5b4714c5a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1650,7 +1650,36 @@ static void evergreen_gpu_init(struct radeon_device *rdev) } } - rdev->config.evergreen.tile_config = gb_addr_config; + /* setup tiling info dword. gb_addr_config is not adequate since it does + * not have bank info, so create a custom tiling dword. + * bits 3:0 num_pipes + * bits 7:4 num_banks + * bits 11:8 group_size + * bits 15:12 row_size + */ + rdev->config.evergreen.tile_config = 0; + switch (rdev->config.evergreen.max_tile_pipes) { + case 1: + default: + rdev->config.evergreen.tile_config |= (0 << 0); + break; + case 2: + rdev->config.evergreen.tile_config |= (1 << 0); + break; + case 4: + rdev->config.evergreen.tile_config |= (2 << 0); + break; + case 8: + rdev->config.evergreen.tile_config |= (3 << 0); + break; + } + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; + rdev->config.evergreen.tile_config |= + ((gb_addr_config & 0x30000000) >> 28) << 12; + WREG32(GB_BACKEND_MAP, gb_backend_map); WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); -- cgit v1.2.3 From 95ccb0f3bdc4438bf470c25450e6a8a6090ca253 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 11 Nov 2010 10:04:53 +0100 Subject: drm/ttm: Fix up a theoretical deadlock A process suspended waiting for a higher sequence or no sequence to unreserve, a bo may be beaten to the reservation by a process with a lower sequence. In that case the first process should give up trying to reserve and return -EAGAIN. In order for that to happen, we must wake waiting processes when we change sequence, so that they have a chance to detect the new sequence. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3ca77dc03915..148a322d8f5d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -224,6 +224,9 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, int ret; while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) { + /** + * Deadlock avoidance for multi-bo reserving. + */ if (use_sequence && bo->seq_valid && (sequence - bo->val_seq < (1 << 31))) { return -EAGAIN; @@ -241,6 +244,14 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, } if (use_sequence) { + /** + * Wake up waiters that may need to recheck for deadlock, + * if we decreased the sequence number. + */ + if (unlikely((bo->val_seq - sequence < (1 << 31)) + || !bo->seq_valid)) + wake_up_all(&bo->event_queue); + bo->val_seq = sequence; bo->seq_valid = true; } else { -- cgit v1.2.3 From fb762a5b37e74023f1793cdf64e40d4da38b30ec Mon Sep 17 00:00:00 2001 From: Jesse Marroquin Date: Wed, 17 Nov 2010 14:26:40 -0600 Subject: ASoC: Add support for MAX98089 CODEC This patch adds initial support for the MAX98089 CODEC. Signed-off-by: Jesse Marroquin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index bc22ee93a75d..470cb93b1d1f 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -28,6 +28,11 @@ #include #include "max98088.h" +enum max98088_type { + MAX98088, + MAX98089, +}; + struct max98088_cdata { unsigned int rate; unsigned int fmt; @@ -36,6 +41,7 @@ struct max98088_cdata { struct max98088_priv { u8 reg_cache[M98088_REG_CNT]; + enum max98088_type devtype; void *control_data; struct max98088_pdata *pdata; unsigned int sysclk; @@ -2040,6 +2046,8 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (max98088 == NULL) return -ENOMEM; + max98088->devtype = id->driver_data; + i2c_set_clientdata(i2c, max98088); max98088->control_data = i2c; max98088->pdata = i2c->dev.platform_data; @@ -2059,7 +2067,8 @@ static int __devexit max98088_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id max98088_i2c_id[] = { - { "max98088", 0 }, + { "max98088", MAX98088 }, + { "max98089", MAX98089 }, { } }; MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); -- cgit v1.2.3 From 09a02fdb919876c01e8f05960750a418b3f7fa48 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 17 Nov 2010 16:34:37 -0500 Subject: cfg80211: fix can_beacon_sec_chan, reenable HT40 This follows wireless-testing 9236d838c920e90708570d9bbd7bb82d30a38130 ("cfg80211: fix extension channel checks to initiate communication") and fixes accidental case fall-through. Without this fix, HT40 is entirely blocked. Signed-off-by: Mark Mentovai Cc: stable@kernel.org Acked-by: Luis R. Rodriguez --- net/wireless/chan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index c8d190d911e4..17cd0c04d139 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -54,8 +54,10 @@ static bool can_beacon_sec_chan(struct wiphy *wiphy, switch (channel_type) { case NL80211_CHAN_HT40PLUS: diff = 20; + break; case NL80211_CHAN_HT40MINUS: diff = -20; + break; default: return false; } -- cgit v1.2.3 From 3105c19c450ac7c18ab28c19d364b588767261b3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 18 Nov 2010 09:15:07 -0800 Subject: ceph: fix readdir EOVERFLOW on 32-bit archs One of the readdir filldir_t callers was passing the raw ceph 64-bit ino instead of the hashed 32-bit one, producing an EOVERFLOW in the filler callback. Fix this by calling the ceph_vino_to_ino() helper to do the conversion. Reported-by: Jan Smets Tested-by: Jan Smets Signed-off-by: Sage Weil --- fs/ceph/dir.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 5f67728ba4d7..7d447af84ec4 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -358,18 +358,22 @@ more: u64 pos = ceph_make_fpos(frag, off); struct ceph_mds_reply_inode *in = rinfo->dir_in[off - fi->offset].in; + struct ceph_vino vino; + ino_t ino; + dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n", off, off - fi->offset, rinfo->dir_nr, pos, rinfo->dir_dname_len[off - fi->offset], rinfo->dir_dname[off - fi->offset], in); BUG_ON(!in); ftype = le32_to_cpu(in->mode) >> 12; + vino.ino = le64_to_cpu(in->ino); + vino.snap = le64_to_cpu(in->snapid); + ino = ceph_vino_to_ino(vino); if (filldir(dirent, rinfo->dir_dname[off - fi->offset], rinfo->dir_dname_len[off - fi->offset], - pos, - le64_to_cpu(in->ino), - ftype) < 0) { + pos, ino, ftype) < 0) { dout("filldir stopping us...\n"); return 0; } -- cgit v1.2.3 From de391d12500ede13faa7ecadbe900a8de1f76cfa Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Thu, 18 Nov 2010 09:06:43 -0800 Subject: Input: fix typo in keycode validation supporting large scancodes Check the input_keymap_entry keycode size (u32) instead of the device's (void*) when validating that keycode value can be stored in the keymap. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=22722 Signed-off-by: Mattia Dongili Tested-by: Norbert Preining Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 7f26ca6ecf75..5edc41aa08f8 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -753,7 +753,7 @@ static int input_default_setkeycode(struct input_dev *dev, if (index >= dev->keycodemax) return -EINVAL; - if (dev->keycodesize < sizeof(dev->keycode) && + if (dev->keycodesize < sizeof(ke->keycode) && (ke->keycode >> (dev->keycodesize * 8))) return -EINVAL; -- cgit v1.2.3 From 3006bc38895895f1a0352c2e17e1a503f35f7e2f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 18 Nov 2010 09:30:42 -0800 Subject: bonding: fix a race in IGMP handling RCU conversion in IGMP code done in net-next-2.6 raised a race in __bond_resend_igmp_join_requests(). It iterates in_dev->mc_list without appropriate protection (RTNL, or read_lock on in_dev->mc_list_lock). Another cpu might delete an entry while we use it and trigger a fault. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bdb68a600382..71a169740d05 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -878,8 +878,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev) rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) { + read_lock(&in_dev->mc_list_lock); for (im = in_dev->mc_list; im; im = im->next) ip_mc_rejoin_group(im); + read_unlock(&in_dev->mc_list_lock); } rcu_read_unlock(); -- cgit v1.2.3 From b52b97a339c0f2d76dfd6a31466d3f1b05c5cf7e Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Thu, 18 Nov 2010 09:32:02 -0800 Subject: MAINTAINERS: Add stmmac maintainer Add STMMAC to the list of supported Ethernet drivers and myself as maintainer. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 88b74a75d932..8b6ca96435ee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1829,6 +1829,13 @@ W: http://www.chelsio.com S: Supported F: drivers/net/cxgb4vf/ +STMMAC ETHERNET DRIVER +M: Giuseppe Cavallaro +L: netdev@vger.kernel.org +W: http://www.stlinux.com +S: Supported +F: drivers/net/stmmac/ + CYBERPRO FB DRIVER M: Russell King L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -- cgit v1.2.3 From ef22b7b65f0eda9015becc7bff225a399914a242 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 18 Nov 2010 09:40:04 -0800 Subject: net: Fix duplicate volatile warning. jiffies is defined as "volatile". extern unsigned long volatile __jiffy_data jiffies; ACCESS_ONCE() uses "volatile". As a result, some compilers warn duplicate `volatile' for ACCESS_ONCE(jiffies). Signed-off-by: Tetsuo Handa Signed-off-by: David S. Miller --- include/net/neighbour.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 55590ab16b3e..6beb1ffc2b7f 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -303,7 +303,7 @@ static inline void neigh_confirm(struct neighbour *neigh) static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) { - unsigned long now = ACCESS_ONCE(jiffies); + unsigned long now = jiffies; if (neigh->used != now) neigh->used = now; -- cgit v1.2.3 From 7d8e76bf9ac3604897f0ce12e8bf09b68c2a2c89 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 16 Nov 2010 19:42:53 +0000 Subject: net: zero kobject in rx_queue_release netif_set_real_num_rx_queues() can decrement and increment the number of rx queues. For example ixgbe does this as features and offloads are toggled. Presumably this could also happen across down/up on most devices if the available resources changed (cpu offlined). The kobject needs to be zero'd in this case so that the state is not preserved across kobject_put()/kobject_init_and_add(). This resolves the following error report. ixgbe 0000:03:00.0: eth2: NIC Link is Up 10 Gbps, Flow Control: RX/TX kobject (ffff880324b83210): tried to init an initialized object, something is seriously wrong. Pid: 1972, comm: lldpad Not tainted 2.6.37-rc18021qaz+ #169 Call Trace: [] kobject_init+0x3a/0x83 [] kobject_init_and_add+0x23/0x57 [] ? mark_lock+0x21/0x267 [] net_rx_queue_update_kobjects+0x63/0xc6 [] netif_set_real_num_rx_queues+0x5f/0x78 [] ixgbe_set_num_queues+0x1c6/0x1ca [ixgbe] [] ixgbe_init_interrupt_scheme+0x1e/0x79c [ixgbe] [] ixgbe_dcbnl_set_state+0x167/0x189 [ixgbe] Signed-off-by: John Fastabend Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index a5ff5a89f376..7f902cad10f8 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -712,15 +712,21 @@ static void rx_queue_release(struct kobject *kobj) map = rcu_dereference_raw(queue->rps_map); - if (map) + if (map) { + RCU_INIT_POINTER(queue->rps_map, NULL); call_rcu(&map->rcu, rps_map_release); + } flow_table = rcu_dereference_raw(queue->rps_flow_table); - if (flow_table) + if (flow_table) { + RCU_INIT_POINTER(queue->rps_flow_table, NULL); call_rcu(&flow_table->rcu, rps_dev_flow_table_release); + } if (atomic_dec_and_test(&first->count)) kfree(first); + else + memset(kobj, 0, sizeof(*kobj)); } static struct kobj_type rx_queue_ktype = { -- cgit v1.2.3 From 3bf30b56c4f0a1c4fae34050b7db4527c92891e8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 18 Nov 2010 12:19:52 +0530 Subject: ath9k_htc: Avoid setting QoS control for non-QoS frames Setting tid information in the TX header is required only for QoS frames. Not handling this case causes severe data loss with some APs. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3d19b5bc937f..29d80ca78393 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -121,7 +121,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) tx_hdr.data_type = ATH9K_HTC_NORMAL; } - if (ieee80211_is_data(fc)) { + if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } -- cgit v1.2.3 From 8ea91226eccf6c8ab9c55054b24c21021d4d9d19 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 18 Nov 2010 10:35:58 -0800 Subject: net: caif: spi: fix potential NULL dereference alloc_netdev() is not checked here for NULL return value. dev is check instead. It might lead to NULL dereference of ndev. Signed-off-by: Vasiliy Kulikov Signed-off-by: David S. Miller --- drivers/net/caif/caif_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 8b4cea57a6c5..20da1996d354 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -635,8 +635,8 @@ int cfspi_spi_probe(struct platform_device *pdev) ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", cfspi_setup); - if (!dev) - return -ENODEV; + if (!ndev) + return -ENOMEM; cfspi = netdev_priv(ndev); netif_stop_queue(ndev); -- cgit v1.2.3 From 1aa46ec91cfd3cc4ab19780f664a3d089bb67173 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 13 Nov 2010 13:42:08 +0000 Subject: ipg.c: remove id [SUNDANCE, 0x1021] ipg.c: The id [SUNDANCE, 0x1021] (=[0x13f0, 0x1021]) is defined at dl2k.h and ipg.c. But this device works better with dl2k driver. This problem is similar with the commit [25cca5352712561fba97bd37c495593d641c1d39 ipg: Remove device claimed by dl2k from pci id table] at 11 Feb 2010. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/ipg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index dc0198092343..aa93655c3aa7 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -88,16 +88,14 @@ static const char *ipg_brand_name[] = { "IC PLUS IP1000 1000/100/10 based NIC", "Sundance Technology ST2021 based NIC", "Tamarack Microelectronics TC9020/9021 based NIC", - "Tamarack Microelectronics TC9020/9021 based NIC", "D-Link NIC IP1000A" }; static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = { { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, - { PCI_VDEVICE(SUNDANCE, 0x1021), 2 }, - { PCI_VDEVICE(DLINK, 0x9021), 3 }, - { PCI_VDEVICE(DLINK, 0x4020), 4 }, + { PCI_VDEVICE(DLINK, 0x9021), 2 }, + { PCI_VDEVICE(DLINK, 0x4020), 3 }, { 0, } }; -- cgit v1.2.3 From d530db0db90378b5674cb78d9c0cfcc83f851a5e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 16 Nov 2010 05:27:51 +0000 Subject: 3c59x: fix build failure on !CONFIG_PCI VORTEX_PCI() could return NULL so it needs to be casted before accessing any member of struct pci_dev. This fixes following build failure. Likewise VORTEX_EISA() was changed also. CC [M] drivers/net/3c59x.o drivers/net/3c59x.c: In function 'acpi_set_WOL': drivers/net/3c59x.c:3211:39: warning: dereferencing 'void *' pointer drivers/net/3c59x.c:3211:39: error: request for member 'current_state' in something not a structure or union make[3]: *** [drivers/net/3c59x.o] Error 1 make[2]: *** [drivers/net/3c59x.o] Error 2 make[1]: *** [sub-make] Error 2 make: *** [all] Error 2 Signed-off-by: Namhyung Kim Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index e1da258bbfb7..0a92436f0538 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -699,7 +699,8 @@ DEFINE_WINDOW_IO(32) #define DEVICE_PCI(dev) NULL #endif -#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL) +#define VORTEX_PCI(vp) \ + ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)) #ifdef CONFIG_EISA #define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL) @@ -707,7 +708,8 @@ DEFINE_WINDOW_IO(32) #define DEVICE_EISA(dev) NULL #endif -#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL) +#define VORTEX_EISA(vp) \ + ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)) /* The action to take with a media selection timer tick. Note that we deviate from the 3Com order by checking 10base2 before AUI. -- cgit v1.2.3 From ed1d77b18c9f4ff06d5b42c65041aa55a1447053 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 18 Nov 2010 10:56:29 -0800 Subject: hardirq.h: needs sched.h if using BKL This really isn't the right thing to do, and strictly speaking we should have the BKL depth count in the thread info right next to the preempt count. The two really do go together. However, since that would involve a patch to all architectures, and the BKL is finally going away, it's simply not worth the effort to do the RightThing(tm). Just re-instate the include that we used to get accidentally from the smp_lock.h one. This is all fallout from the same old "BKL: remove extraneous #include " commit. Reported-by: Ingo Molnar Tested-by: Randy Dunlap Cc: Arnd Bergmann Signed-off-by: Linus Torvalds --- include/linux/hardirq.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 714da7e5d10c..32f9fd6619b4 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -94,6 +94,7 @@ #define in_nmi() (preempt_count() & NMI_MASK) #if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL) +# include # define PREEMPT_INATOMIC_BASE (current->lock_depth >= 0) #else # define PREEMPT_INATOMIC_BASE 0 -- cgit v1.2.3 From 93908d192686d8285dd6441ff855df92a40103d2 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 17 Nov 2010 01:44:24 +0000 Subject: ipv6: Expose IFLA_PROTINFO timer values in msecs instead of jiffies IFLA_PROTINFO exposes timer related per device settings in jiffies. Change it to expose these values in msecs like the sysctl interface does. I did not find any users of IFLA_PROTINFO which rely on any of these values and even if there are, they are likely already broken because there is no way for them to reliably convert such a value to another time format. Signed-off-by: Thomas Graf Cc: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b41ce0f0d514..52b7df74e4c7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3798,8 +3798,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_AUTOCONF] = cnf->autoconf; array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; - array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval; - array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay; + array[DEVCONF_RTR_SOLICIT_INTERVAL] = + jiffies_to_msecs(cnf->rtr_solicit_interval); + array[DEVCONF_RTR_SOLICIT_DELAY] = + jiffies_to_msecs(cnf->rtr_solicit_delay); array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; #ifdef CONFIG_IPV6_PRIVACY array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; @@ -3813,7 +3815,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; #ifdef CONFIG_IPV6_ROUTER_PREF array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; - array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; + array[DEVCONF_RTR_PROBE_INTERVAL] = + jiffies_to_msecs(cnf->rtr_probe_interval); #ifdef CONFIG_IPV6_ROUTE_INFO array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; #endif -- cgit v1.2.3 From 2811036a19624168ff9342bb85421dbbb1d2ac0d Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Thu, 18 Nov 2010 18:28:20 -0500 Subject: Fix build failure at cx25821-video driver Kernel build fail for cx25821-video has depends on smp_lock.h header file, but the dependency is removed in recent commit 451a3c24b013. Signed-off-by: Youquan Song Signed-off-by: Linus Torvalds --- drivers/staging/cx25821/cx25821.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h index acfd0176a184..c94000125782 100644 --- a/drivers/staging/cx25821/cx25821.h +++ b/drivers/staging/cx25821/cx25821.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 18a31e1e282f9ed563b131526a88162ccbe04ee3 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 17 Nov 2010 04:12:02 +0000 Subject: ipv6: Expose reachable and retrans timer values as msecs Expose reachable and retrans timer values in msecs instead of jiffies. Both timer values are already exposed as msecs in the neighbour table netlink interface. The creation timestamp format with increased precision is kept but cleaned up. Signed-off-by: Thomas Graf Cc: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 52b7df74e4c7..2fc35b32df9e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -98,7 +98,11 @@ #endif #define INFINITY_LIFE_TIME 0xFFFFFFFF -#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) + +static inline u32 cstamp_delta(unsigned long cstamp) +{ + return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; +} #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) #define ADDRCONF_TIMER_FUZZ (HZ / 4) @@ -3444,10 +3448,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, { struct ifa_cacheinfo ci; - ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); - ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); + ci.cstamp = cstamp_delta(cstamp); + ci.tstamp = cstamp_delta(tstamp); ci.ifa_prefered = preferred; ci.ifa_valid = valid; @@ -3932,10 +3934,9 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); ci.max_reasm_len = IPV6_MAXPLEN; - ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); - ci.reachable_time = idev->nd_parms->reachable_time; - ci.retrans_time = idev->nd_parms->retrans_time; + ci.tstamp = cstamp_delta(idev->tstamp); + ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); + ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); -- cgit v1.2.3 From 925e277f5221defdc53cbef1ac3ed1803fa32357 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 16 Nov 2010 09:40:02 +0000 Subject: net: irda: irttp: sync error paths of data- and udata-requests irttp_data_request() returns meaningful errorcodes, while irttp_udata_request() just returns -1 in similar situations. Sync the two and the loglevels of the accompanying output. Signed-off-by: Wolfram Sang Cc: Samuel Ortiz Cc: David Miller Signed-off-by: David S. Miller --- net/irda/irttp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 6cfaeaf2a370..f6054f9ccbe3 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -550,7 +550,7 @@ EXPORT_SYMBOL(irttp_close_tsap); */ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) { - int ret = -1; + int ret; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); @@ -566,13 +566,14 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) /* Check that nothing bad happens */ if (!self->connected) { - IRDA_DEBUG(1, "%s(), Not connected\n", __func__); + IRDA_WARNING("%s(), Not connected\n", __func__); + ret = -ENOTCONN; goto err; } if (skb->len > self->max_seg_size) { - IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n", - __func__); + IRDA_ERROR("%s(), UData is too large for IrLAP!\n", __func__); + ret = -EMSGSIZE; goto err; } -- cgit v1.2.3 From dba4490d22a496f9b7c21919cf3effbed5851213 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 18 Nov 2010 08:20:57 +0000 Subject: netfilter: fix IP_VS dependencies When NF_CONNTRACK is enabled, IP_VS uses conntrack symbols. Therefore IP_VS can't be linked statically when conntrack is built modular. Reported-by: Justin P. Mattock Tested-by: Justin P. Mattock Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/ipvs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index a22dac227055..70bd1d0774c6 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig @@ -4,6 +4,7 @@ menuconfig IP_VS tristate "IP virtual server support" depends on NET && INET && NETFILTER + depends on (NF_CONNTRACK || NF_CONNTRACK=n) ---help--- IP Virtual Server support will let you build a high-performance virtual server based on cluster of two or more real servers. This -- cgit v1.2.3 From 2b35f4d9cab365d37c7b34ce51e1c1144c312d05 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 12:27:31 -0800 Subject: kernel-doc: escape xml for structs scripts/kernel-doc was leaving unescaped '<', '>', and '&' in generated xml output for structs. This causes xml parser errors. Convert these characters to "<", ">", and "&" as needed to prevent errors. Most of the conversion was already done; complete it just before output. Documentation/DocBook/device-drivers.xml:41883: parser error : StartTag: invalid element name #define INPUT_KEYMAP_BY_INDEX (1 << 0) Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index cdb6dc1f6458..39580a5dc5df 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -5,7 +5,7 @@ use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh ## ## Copyright (C) 2001 Simon Huggins ## -## Copyright (C) 2005-2009 Randy Dunlap ## +## Copyright (C) 2005-2010 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -453,7 +453,7 @@ sub output_highlight { if ($output_mode eq "html" || $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: - $contents =~ s/\\\\\\/&/g; + $contents =~ s/\\\\\\/\&/g; } # print STDERR "contents b4:$contents\n"; eval $dohighlight; @@ -770,7 +770,11 @@ sub output_struct_xml(%) { print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { - print "$parameter\n"; + my $prm = $parameter; + # convert data read & converted thru xml_escape() into &xyz; format: + # This allows us to have #define macros interspersed in a struct. + $prm =~ s/\\\\\\/\&/g; + print "$prm\n"; next; } @@ -1701,6 +1705,8 @@ sub push_parameter($$$) { } } + $param = xml_escape($param); + # strip spaces from $param so that it is one continous string # on @parameterlist; # this fixes a problem where check_sections() cannot find -- cgit v1.2.3 From 09c9feb94672bdb3ca6d424a292ffc26eff8ca0b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Nov 2010 12:27:32 -0800 Subject: Documentation: make configfs example code simpler, clearer If "p" is NULL then it will cause an oops when we pass it to simple_strtoul(). In this case "p" can not be NULL so I removed the check. I also changed the check a little to make it more explicit that we are testing whether p points to the NUL char. Signed-off-by: Dan Carpenter Acked-by: Joel Becker Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/filesystems/configfs/configfs_example_explicit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/configfs/configfs_example_explicit.c b/Documentation/filesystems/configfs/configfs_example_explicit.c index d428cc9f07f3..fd53869f5633 100644 --- a/Documentation/filesystems/configfs/configfs_example_explicit.c +++ b/Documentation/filesystems/configfs/configfs_example_explicit.c @@ -89,7 +89,7 @@ static ssize_t childless_storeme_write(struct childless *childless, char *p = (char *) page; tmp = simple_strtoul(p, &p, 10); - if (!p || (*p && (*p != '\n'))) + if ((*p != '\0') && (*p != '\n')) return -EINVAL; if (tmp > INT_MAX) -- cgit v1.2.3 From ebde7b062cd9e2ea968c93f23f73dd28c0a192d1 Mon Sep 17 00:00:00 2001 From: Bernhard Walle Date: Thu, 18 Nov 2010 12:27:33 -0800 Subject: Documentation/gpio.txt: explain poll/select usage Add a bit more information how to use poll(2) on GPIO value files correctly. For me it was not clear that I need to poll(2) for POLLPRI|POLLERR or select(2) for exceptfds. Signed-off-by: Bernhard Walle Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 9633da01ff46..792faa3c06cf 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -617,6 +617,16 @@ and have the following read/write attributes: is configured as an output, this value may be written; any nonzero value is treated as high. + If the pin can be configured as interrupt-generating interrupt + and if it has been configured to generate interrupts (see the + description of "edge"), you can poll(2) on that file and + poll(2) will return whenever the interrupt was triggered. If + you use poll(2), set the events POLLPRI and POLLERR. If you + use select(2), set the file descriptor in exceptfds. After + poll(2) returns, either lseek(2) to the beginning of the sysfs + file and read the new value or close the file and re-open it + to read the value. + "edge" ... reads as either "none", "rising", "falling", or "both". Write these strings to select the signal edge(s) that will make poll(2) on the "value" file return. -- cgit v1.2.3 From f99e0e98f95bbe8833bd96c314b71ef859851bc5 Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Thu, 18 Nov 2010 12:27:34 -0800 Subject: Documentation: change email address for Hans Koch My old mail address doesn't exist anymore. This changes all occurrences to my new address. Signed-off-by: Hans J. Koch Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/DocBook/uio-howto.tmpl | 6 +++--- Documentation/hwmon/lm93 | 2 +- Documentation/hwmon/max6650 | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 4d4ce0e61e42..b4665b9c40b0 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -16,7 +16,7 @@
- hjk@linutronix.de + hjk@hansjkoch.de
@@ -114,7 +114,7 @@ GPL version 2. If you know of any translations for this document, or you are interested in translating it, please email me -hjk@linutronix.de. +hjk@hansjkoch.de. @@ -171,7 +171,7 @@ interested in translating it, please email me Feedback Find something wrong with this document? (Or perhaps something right?) I would love to hear from you. Please email me at - hjk@linutronix.de. + hjk@hansjkoch.de. diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93 index ac711f357faf..7a10616d0b44 100644 --- a/Documentation/hwmon/lm93 +++ b/Documentation/hwmon/lm93 @@ -11,7 +11,7 @@ Authors: Mark M. Hoffman Ported to 2.6 by Eric J. Bowersox Adapted to 2.6.20 by Carsten Emde - Modified for mainline integration by Hans J. Koch + Modified for mainline integration by Hans J. Koch Module Parameters ----------------- diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650 index 8be7beb9e3e8..c565650fcfc6 100644 --- a/Documentation/hwmon/max6650 +++ b/Documentation/hwmon/max6650 @@ -8,7 +8,7 @@ Supported chips: Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf Authors: - Hans J. Koch + Hans J. Koch John Morris Claus Gindhart -- cgit v1.2.3 From e4fabad30eaba5bb78cd8d47885f1b705a0918a0 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 18 Nov 2010 12:27:35 -0800 Subject: Documentation/development-process: use -next trees instead of staging This is confusing, as we have "staging" trees for drivers/staging. Call them -next trees. Signed-off-by: Andres Salomon Acked-by: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/development-process/2.Process | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index 97726eba6102..ae8127c1a780 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process @@ -154,7 +154,7 @@ The stages that a patch goes through are, generally: inclusion, it should be accepted by a relevant subsystem maintainer - though this acceptance is not a guarantee that the patch will make it all the way to the mainline. The patch will show up in the maintainer's - subsystem tree and into the staging trees (described below). When the + subsystem tree and into the -next trees (described below). When the process works, this step leads to more extensive review of the patch and the discovery of any problems resulting from the integration of this patch with work being done by others. @@ -236,7 +236,7 @@ finding the right maintainer. Sending patches directly to Linus is not normally the right way to go. -2.4: STAGING TREES +2.4: NEXT TREES The chain of subsystem trees guides the flow of patches into the kernel, but it also raises an interesting question: what if somebody wants to look @@ -250,7 +250,7 @@ changes land in the mainline kernel. One could pull changes from all of the interesting subsystem trees, but that would be a big and error-prone job. -The answer comes in the form of staging trees, where subsystem trees are +The answer comes in the form of -next trees, where subsystem trees are collected for testing and review. The older of these trees, maintained by Andrew Morton, is called "-mm" (for memory management, which is how it got started). The -mm tree integrates patches from a long list of subsystem @@ -275,7 +275,7 @@ directory at: Use of the MMOTM tree is likely to be a frustrating experience, though; there is a definite chance that it will not even compile. -The other staging tree, started more recently, is linux-next, maintained by +The other -next tree, started more recently, is linux-next, maintained by Stephen Rothwell. The linux-next tree is, by design, a snapshot of what the mainline is expected to look like after the next merge window closes. Linux-next trees are announced on the linux-kernel and linux-next mailing -- cgit v1.2.3 From f830673f6aa28741ff6993deade587c8550c1dd3 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 18 Nov 2010 12:27:36 -0800 Subject: Documentation/development-process: more staging info Document things that I would've liked to have known when submitting a driver to gregkh for staging. Signed-off-by: Andres Salomon Acked-by: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/development-process/2.Process | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index ae8127c1a780..911a45186340 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process @@ -303,12 +303,25 @@ volatility of linux-next tends to make it a difficult development target. See http://lwn.net/Articles/289013/ for more information on this topic, and stay tuned; much is still in flux where linux-next is involved. -Besides the mmotm and linux-next trees, the kernel source tree now contains -the drivers/staging/ directory and many sub-directories for drivers or -filesystems that are on their way to being added to the kernel tree -proper, but they remain in drivers/staging/ while they still need more -work. - +2.4.1: STAGING TREES + +The kernel source tree now contains the drivers/staging/ directory, where +many sub-directories for drivers or filesystems that are on their way to +being added to the kernel tree live. They remain in drivers/staging while +they still need more work; once complete, they can be moved into the +kernel proper. This is a way to keep track of drivers that aren't +up to Linux kernel coding or quality standards, but people may want to use +them and track development. + +Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree. +Drivers that still need work are sent to him, with each driver having +its own subdirectory in drivers/staging/. Along with the driver source +files, a TODO file should be present in the directory as well. The TODO +file lists the pending work that the driver needs for acceptance into +the kernel proper, as well as a list of people that should be Cc'd for any +patches to the driver. Staging drivers that don't currently build should +have their config entries depend upon CONFIG_BROKEN. Once they can +be successfully built without outside patches, CONFIG_BROKEN can be removed. 2.5: TOOLS -- cgit v1.2.3 From 5d3efe0735350ca9329259f34ac6a84b36dd83f2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 12:27:37 -0800 Subject: MAINTAINERS: update documentation entries Update kernel-doc and Documentation maintainers info. Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8e6548dbd5db..f51ec0a22ff9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2008,6 +2008,7 @@ F: drivers/hwmon/dme1737.c DOCBOOK FOR DOCUMENTATION M: Randy Dunlap S: Maintained +F: scripts/kernel-doc DOCKING STATION DRIVER M: Shaohua Li @@ -2018,6 +2019,7 @@ F: drivers/acpi/dock.c DOCUMENTATION M: Randy Dunlap L: linux-doc@vger.kernel.org +T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/ S: Maintained F: Documentation/ -- cgit v1.2.3 From be66305718bee9927e6acc6b75618ce3cd745718 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Nov 2010 17:18:08 -0500 Subject: drm/radeon/kms: fix i2c pad masks on rs4xx These got lost in the last i2c cleanup. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=23222 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b7ea269549c..3bddea5b5295 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -571,6 +571,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde } if (clk_mask && data_mask) { + /* system specific masks */ i2c.mask_clk_mask = clk_mask; i2c.mask_data_mask = data_mask; i2c.a_clk_mask = clk_mask; @@ -579,7 +580,19 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde i2c.en_data_mask = data_mask; i2c.y_clk_mask = clk_mask; i2c.y_data_mask = data_mask; + } else if ((ddc_line == RADEON_GPIOPAD_MASK) || + (ddc_line == RADEON_MDGPIO_MASK)) { + /* default gpiopad masks */ + i2c.mask_clk_mask = (0x20 << 8); + i2c.mask_data_mask = 0x80; + i2c.a_clk_mask = (0x20 << 8); + i2c.a_data_mask = 0x80; + i2c.en_clk_mask = (0x20 << 8); + i2c.en_data_mask = 0x80; + i2c.y_clk_mask = (0x20 << 8); + i2c.y_data_mask = 0x80; } else { + /* default masks for ddc pads */ i2c.mask_clk_mask = RADEON_GPIO_EN_1; i2c.mask_data_mask = RADEON_GPIO_EN_0; i2c.a_clk_mask = RADEON_GPIO_A_1; -- cgit v1.2.3 From 164bcb94bc821fcbac752e809b4ac7c6f15d13b5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Nov 2010 11:37:18 -0500 Subject: drm/radeon/kms: i2c s/sprintf/snprintf/g for safety As per advice from Jean Delvare. Signed-off-by: Alex Deucher Acked-by: Jean Delvare Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index d263bd1a0d80..ded2a45bc95c 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -896,7 +896,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, ((rdev->family <= CHIP_RS480) || ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) { /* set the radeon hw i2c adapter */ - sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c hw bus %s", name); i2c->adapter.algo = &radeon_i2c_algo; ret = i2c_add_adapter(&i2c->adapter); if (ret) { @@ -905,7 +906,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, } } else { /* set the radeon bit adapter */ - sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c bit bus %s", name); i2c->adapter.algo_data = &i2c->algo.bit; i2c->algo.bit.pre_xfer = pre_xfer; i2c->algo.bit.post_xfer = post_xfer; @@ -946,7 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; - sprintf(i2c->adapter.name, "Radeon aux bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon aux bus %s", name); i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.algo_data = &i2c->algo.dp; i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; -- cgit v1.2.3 From 9045d47ea362e6a3727ee3f1b69a1b656976772e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 18 Nov 2010 17:14:46 -0800 Subject: Revert "xen/privcmd: create address space to allow writable mmaps" This reverts commit 24a89b5be4cf2b7f1b49b56b6cb4a7b71fccf241. We should no longer need an address space now that we're correctly setting VM_PFNMAP on our vmas. Conflicts: drivers/xen/xenfs/super.c Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/super.c | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 990ee42167a1..1aa389719846 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include @@ -24,28 +22,12 @@ MODULE_DESCRIPTION("Xen filesystem"); MODULE_LICENSE("GPL"); -static int xenfs_set_page_dirty(struct page *page) -{ - return !TestSetPageDirty(page); -} - -static const struct address_space_operations xenfs_aops = { - .set_page_dirty = xenfs_set_page_dirty, -}; - -static struct backing_dev_info xenfs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, -}; - static struct inode *xenfs_make_inode(struct super_block *sb, int mode) { struct inode *ret = new_inode(sb); if (ret) { ret->i_mode = mode; - ret->i_mapping->a_ops = &xenfs_aops; - ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info; ret->i_uid = ret->i_gid = 0; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; @@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = { static int __init xenfs_init(void) { - int err; - if (!xen_domain()) { - printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n"); - return 0; - } - - err = register_filesystem(&xenfs_type); - if (err) { - printk(KERN_ERR "xenfs: Unable to register filesystem!\n"); - goto out; - } - - err = bdi_init(&xenfs_backing_dev_info); - if (err) - unregister_filesystem(&xenfs_type); - - out: + if (xen_domain()) + return register_filesystem(&xenfs_type); - return err; + printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); + return 0; } static void __exit xenfs_exit(void) -- cgit v1.2.3 From bc7fc5e33e1a093e5f9e196595843bb096471586 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 18 Nov 2010 22:32:17 -0800 Subject: xen/evtchn: the evtchn device is non-seekable Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/evtchn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index fec6ba3c08a8..dd8e5e0f1935 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -431,7 +431,7 @@ static int evtchn_open(struct inode *inode, struct file *filp) filp->private_data = u; - return 0; + return nonseekable_open(inode, filp);; } static int evtchn_release(struct inode *inode, struct file *filp) @@ -467,7 +467,7 @@ static const struct file_operations evtchn_fops = { .fasync = evtchn_fasync, .open = evtchn_open, .release = evtchn_release, - .llseek = noop_llseek, + .llseek = no_llseek, }; static struct miscdevice evtchn_miscdev = { -- cgit v1.2.3 From b5d827b641b192ceb6968c21feb544c744e43108 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 7 Dec 2009 17:10:27 -0800 Subject: xen: make evtchn's name less generic Signed-off-by: Ian Campbell Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index eb8a78d77d9d..533a199e7a3f 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -8,9 +8,12 @@ obj-$(CONFIG_BLOCK) += biomerge.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o -obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o +obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pci.o + +xen-evtchn-y := evtchn.o + -- cgit v1.2.3 From 51311d0a5c69adaec582080ad8d9b174a44dfd7a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Nov 2010 09:10:42 +0000 Subject: drm/i915: Do not hold mutex when faulting in user addresses Linus Torvalds found that it was rather trivial to trigger a system freeze: In fact, with lockdep, I don't even need to do the sysrq-d thing: it shows the bug as it happens. It's the X server taking the same lock recursively. Here's the problem: ============================================= [ INFO: possible recursive locking detected ] 2.6.37-rc2-00012-gbdbd01a #7 --------------------------------------------- Xorg/2816 is trying to acquire lock: (&dev->struct_mutex){+.+.+.}, at: [] i915_gem_fault+0x50/0x17e but task is already holding lock: (&dev->struct_mutex){+.+.+.}, at: [] i915_mutex_lock_interruptible+0x28/0x4a other info that might help us debug this: 2 locks held by Xorg/2816: #0: (&dev->struct_mutex){+.+.+.}, at: [] i915_mutex_lock_interruptible+0x28/0x4a #1: (&mm->mmap_sem){++++++}, at: [] page_fault+0x156/0x37b This recursion was introduced by rearranging the locking to avoid the double locking on the fast path (4f27b5d and fbd5a26d) and the introduction of the prefault to encourage the fast paths (b5e4f2b). In order to undo the problem, we rearrange the code to perform the access validation upfront, attempt to prefault and then fight for control of the mutex. the best case scenario where the mutex is uncontended the prefaulting is not wasted. Reported-and-tested-by: Linus Torvalds Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 63 ++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 781c26c37b38..17b1cba3b5f1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -547,6 +547,19 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj_priv; int ret = 0; + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_WRITE, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) + return -EFAULT; + + ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr, + args->size); + if (ret) + return -EFAULT; + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -564,23 +577,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, goto out; } - if (args->size == 0) - goto out; - - if (!access_ok(VERIFY_WRITE, - (char __user *)(uintptr_t)args->data_ptr, - args->size)) { - ret = -EFAULT; - goto out; - } - - ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr, - args->size); - if (ret) { - ret = -EFAULT; - goto out; - } - ret = i915_gem_object_get_pages_or_evict(obj); if (ret) goto out; @@ -981,7 +977,20 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_pwrite *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - int ret = 0; + int ret; + + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_READ, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) + return -EFAULT; + + ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr, + args->size); + if (ret) + return -EFAULT; ret = i915_mutex_lock_interruptible(dev); if (ret) @@ -994,30 +1003,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, } obj_priv = to_intel_bo(obj); - /* Bounds check destination. */ if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; goto out; } - if (args->size == 0) - goto out; - - if (!access_ok(VERIFY_READ, - (char __user *)(uintptr_t)args->data_ptr, - args->size)) { - ret = -EFAULT; - goto out; - } - - ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr, - args->size); - if (ret) { - ret = -EFAULT; - goto out; - } - /* We can only do the GTT pwrite on untiled buffers, as otherwise * it would end up going through the fenced access, and we'll get * different detiling behavior between reading and writing. -- cgit v1.2.3 From c9a1c4cded955176479a28556f546d3d015aee91 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Nov 2010 10:58:37 +0000 Subject: drm/i915/crt: Introduce struct intel_crt We will use this structure in future patches to store CRT specific information on the encoder. Split out and tweaked from a patch by Keith Packard. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 64 +++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c55c77043357..e38bc6769180 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -34,6 +34,16 @@ #include "i915_drm.h" #include "i915_drv.h" +struct intel_crt { + struct intel_encoder base; +}; + +static struct intel_crt *intel_attached_crt(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_crt, base); +} + static void intel_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -277,13 +287,12 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; } -static bool intel_crt_detect_ddc(struct drm_encoder *encoder) +static bool intel_crt_detect_ddc(struct intel_crt *crt) { - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; /* CRT should always be at 0, but check anyway */ - if (intel_encoder->type != INTEL_OUTPUT_ANALOG) + if (crt->base.type != INTEL_OUTPUT_ANALOG) return false; if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) { @@ -291,7 +300,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) return true; } - if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) { + if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); return true; } @@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) } static enum drm_connector_status -intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder) +intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt) { - struct drm_encoder *encoder = &intel_encoder->base; + struct drm_encoder *encoder = &crt->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -434,7 +443,7 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_crt *crt = intel_attached_crt(connector); struct drm_crtc *crtc; int dpms_mode; enum drm_connector_status status; @@ -447,24 +456,25 @@ intel_crt_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; } - if (intel_crt_detect_ddc(&encoder->base)) + if (intel_crt_detect_ddc(crt)) return connector_status_connected; if (!force) return connector->status; /* for pre-945g platforms use load detect */ - if (encoder->base.crtc && encoder->base.crtc->enabled) { - status = intel_crt_load_detect(encoder->base.crtc, encoder); + crtc = crt->base.base.crtc; + if (crtc && crtc->enabled) { + status = intel_crt_load_detect(crtc, crt); } else { - crtc = intel_get_load_detect_pipe(encoder, connector, + crtc = intel_get_load_detect_pipe(&crt->base, connector, NULL, &dpms_mode); if (crtc) { - if (intel_crt_detect_ddc(&encoder->base)) + if (intel_crt_detect_ddc(crt)) status = connector_status_connected; else - status = intel_crt_load_detect(crtc, encoder); - intel_release_load_detect_pipe(encoder, + status = intel_crt_load_detect(crtc, crt); + intel_release_load_detect_pipe(&crt->base, connector, dpms_mode); } else status = connector_status_unknown; @@ -536,17 +546,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = { void intel_crt_init(struct drm_device *dev) { struct drm_connector *connector; - struct intel_encoder *intel_encoder; + struct intel_crt *crt; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; - intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL); - if (!intel_encoder) + crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL); + if (!crt) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(crt); return; } @@ -554,20 +564,20 @@ void intel_crt_init(struct drm_device *dev) drm_connector_init(dev, &intel_connector->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs, + drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - intel_connector_attach_encoder(intel_connector, intel_encoder); + intel_connector_attach_encoder(intel_connector, &crt->base); - intel_encoder->type = INTEL_OUTPUT_ANALOG; - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); - intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + crt->base.type = INTEL_OUTPUT_ANALOG; + crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | + 1 << INTEL_ANALOG_CLONE_BIT | + 1 << INTEL_SDVO_LVDS_CLONE_BIT); + crt->base.crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs); + drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); -- cgit v1.2.3 From e7dbb2f2f8ac843ab5e4d6a8e9a71d16089d324b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 16 Nov 2010 16:03:53 +0800 Subject: drm/i915: Take advantage of auto-polling CRT hotplug detection on PCH hardware Both IBX and CPT have an automatic hotplug detection mode which appears to work reliably enough that we can dispense with the manual force hotplug trigger stuff. This means that hotplug detection is as simple as reading the current hotplug register values. The first time the hotplug detection is activated, the code synchronously waits for a hotplug sequence in case the hardware hasn't bothered to do a detection cycle since being initialized. Signed-off-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 95 ++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e38bc6769180..8df574316063 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -34,8 +34,17 @@ #include "i915_drm.h" #include "i915_drv.h" +/* Here's the desired hotplug mode */ +#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ + ADPA_CRT_HOTPLUG_WARMUP_10MS | \ + ADPA_CRT_HOTPLUG_SAMPLE_4S | \ + ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ + ADPA_CRT_HOTPLUG_VOLREF_325MV | \ + ADPA_CRT_HOTPLUG_ENABLE) + struct intel_crt { struct intel_encoder base; + bool force_hotplug_required; }; static struct intel_crt *intel_attached_crt(struct drm_connector *connector) @@ -139,7 +148,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); } - adpa = 0; + adpa = ADPA_HOTPLUG_BITS; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) adpa |= ADPA_HSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -167,53 +176,44 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = dev->dev_private; - u32 adpa, temp; + u32 adpa; bool ret; - bool turn_off_dac = false; - temp = adpa = I915_READ(PCH_ADPA); + /* The first time through, trigger an explicit detection cycle */ + if (crt->force_hotplug_required) { + bool turn_off_dac = HAS_PCH_SPLIT(dev); + u32 save_adpa; - if (HAS_PCH_SPLIT(dev)) - turn_off_dac = true; - - adpa &= ~ADPA_CRT_HOTPLUG_MASK; - if (turn_off_dac) - adpa &= ~ADPA_DAC_ENABLE; - - /* disable HPD first */ - I915_WRITE(PCH_ADPA, adpa); - (void)I915_READ(PCH_ADPA); - - adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | - ADPA_CRT_HOTPLUG_WARMUP_10MS | - ADPA_CRT_HOTPLUG_SAMPLE_4S | - ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */ - ADPA_CRT_HOTPLUG_VOLREF_325MV | - ADPA_CRT_HOTPLUG_ENABLE | - ADPA_CRT_HOTPLUG_FORCE_TRIGGER); - - DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); - I915_WRITE(PCH_ADPA, adpa); - - if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, - 1000)) - DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); - - if (turn_off_dac) { - /* Make sure hotplug is enabled */ - I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE); - (void)I915_READ(PCH_ADPA); + crt->force_hotplug_required = 0; + + save_adpa = adpa = I915_READ(PCH_ADPA); + DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); + + adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; + if (turn_off_dac) + adpa &= ~ADPA_DAC_ENABLE; + + I915_WRITE(PCH_ADPA, adpa); + + if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + 1000)) + DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); + + if (turn_off_dac) { + I915_WRITE(PCH_ADPA, save_adpa); + POSTING_READ(PCH_ADPA); + } } /* Check the status to see if both blue and green are on now */ adpa = I915_READ(PCH_ADPA); - adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK; - if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) || - (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO)) + if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else ret = false; + DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); return ret; } @@ -452,8 +452,10 @@ intel_crt_detect(struct drm_connector *connector, bool force) if (intel_crt_detect_hotplug(connector)) { DRM_DEBUG_KMS("CRT detected via hotplug\n"); return connector_status_connected; - } else + } else { + DRM_DEBUG_KMS("CRT not detected via hotplug\n"); return connector_status_disconnected; + } } if (intel_crt_detect_ddc(crt)) @@ -587,5 +589,22 @@ void intel_crt_init(struct drm_device *dev) else connector->polled = DRM_CONNECTOR_POLL_CONNECT; + /* + * Configure the automatic hotplug detection stuff + */ + crt->force_hotplug_required = 0; + if (HAS_PCH_SPLIT(dev)) { + u32 adpa; + + adpa = I915_READ(PCH_ADPA); + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + adpa |= ADPA_HOTPLUG_BITS; + I915_WRITE(PCH_ADPA, adpa); + POSTING_READ(PCH_ADPA); + + DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); + crt->force_hotplug_required = 1; + } + dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; } -- cgit v1.2.3 From 16c59ef33b389217c29122235e475557bc1412a1 Mon Sep 17 00:00:00 2001 From: Alex Shi Date: Fri, 19 Nov 2010 09:33:55 +0000 Subject: drm/i915: Disable FBC on Ironlake to save 1W Frame buffer compression is broken on Ironlake due to buggy hardware. Currently it is disabled through chicken bits, but it still consumes over 1W more than if we simply never attempt to enable the FBC code paths. Signed-off-by: Alex Shi Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 80745f85902c..f737960712e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -150,7 +150,8 @@ static const struct intel_device_info intel_ironlake_d_info = { static const struct intel_device_info intel_ironlake_m_info = { .gen = 5, .is_mobile = 1, - .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_fbc = 0, /* disabled due to buggy hardware */ .has_bsd_ring = 1, }; -- cgit v1.2.3 From 2811fe2beb7cb9f34eef4bc9627dcabb401bc05e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 19 Nov 2010 15:48:06 +0800 Subject: ASoC: uda134x - set reg_cache_default to uda134x_reg After checking the code in 2.6.36, I found this is missing during multi-component conversion. Signed-off-by: Axel Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 7540a509a6f5..464f0cfa4c7a 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -597,6 +597,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .resume = uda134x_soc_resume, .reg_cache_size = sizeof(uda134x_reg), .reg_word_size = sizeof(u8), + .reg_cache_default = uda134x_reg, .reg_cache_step = 1, .read = uda134x_read_reg_cache, .write = uda134x_write, -- cgit v1.2.3 From 5a9ae68a349aa076bc8557ee2fcf865574459282 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 19 Nov 2010 09:56:44 -0500 Subject: ext4: ext4_fill_super shouldn't return 0 on corruption At the start of ext4_fill_super, ret is set to -EINVAL, and any failure path out of that function returns ret. However, the generic_check_addressable clause sets ret = 0 (if it passes), which means that a subsequent failure (e.g. a group checksum error) returns 0 even though the mount should fail. This causes vfs_kern_mount in turn to think that the mount succeeded, leading to an oops. A simple fix is to avoid using ret for the generic_check_addressable check, which was last changed in commit 30ca22c70e3ef0a96ff84de69cd7e8561b416cb2. Signed-off-by: Darrick J. Wong Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ef09d1443d1a..14ada8c50c43 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3265,13 +3265,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * Test whether we have more sectors than will fit in sector_t, * and whether the max offset is addressable by the page cache. */ - ret = generic_check_addressable(sb->s_blocksize_bits, + err = generic_check_addressable(sb->s_blocksize_bits, ext4_blocks_count(es)); - if (ret) { + if (err) { ext4_msg(sb, KERN_ERR, "filesystem" " too large to mount safely on this system"); if (sizeof(sector_t) < 8) ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); + ret = err; goto failed_mount; } -- cgit v1.2.3 From d9efd2af461abb7b54c49c1b7e654d496dd1d379 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Thu, 18 Nov 2010 23:44:45 +0000 Subject: be2net: Fix to avoid firmware update when interface is not open. Since interrupts are enabled only when open is called on the interface, Attempting a firmware update operation when interface is down could lead to partial success or failure of operation. This fix fails the request if netif_running is false. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c36cd2ffbadc..93354eee2cfd 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2458,6 +2458,12 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) int status, i = 0, num_imgs = 0; const u8 *p; + if (!netif_running(adapter->netdev)) { + dev_err(&adapter->pdev->dev, + "Firmware load not allowed (interface is down)\n"); + return -EPERM; + } + strcpy(fw_file, func); status = request_firmware(&fw, fw_file, &adapter->pdev->dev); -- cgit v1.2.3 From 0302b8622ce696af1cda22fcf207d3793350e896 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 13:02:37 +0000 Subject: net: fix kernel-doc for sk_filter_rcu_release Fix kernel-doc warning for sk_filter_rcu_release(): Warning(net/core/filter.c:586): missing initial short description on line: * sk_filter_rcu_release: Release a socket filter by rcu_head Signed-off-by: Randy Dunlap Cc: "David S. Miller" Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- net/core/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 23e9b2a6b4c8..c1ee800bc080 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -589,7 +589,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) EXPORT_SYMBOL(sk_chk_filter); /** - * sk_filter_rcu_release: Release a socket filter by rcu_head + * sk_filter_rcu_release - Release a socket filter by rcu_head * @rcu: rcu_head that contains the sk_filter to free */ static void sk_filter_rcu_release(struct rcu_head *rcu) -- cgit v1.2.3 From b1353e4f40f6179ab26a3bb1b2e1fe29ffe534f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 19 Nov 2010 15:29:19 +0100 Subject: sata_via: apply magic FIFO fix to vt6420 too vt6420 has the same FIFO overflow problem as vt6421 when combined with certain devices. This patch applies the magic fix to vt6420 too. Signed-off-by: Tejun Heo Reported-by: Martin Qvist Reported-by: Peter Zijlstra Cc: Joseph Chan Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/sata_via.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index c21589986c69..8b677bbf2d37 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -538,7 +538,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) return 0; } -static void svia_configure(struct pci_dev *pdev) +static void svia_configure(struct pci_dev *pdev, int board_id) { u8 tmp8; @@ -577,7 +577,7 @@ static void svia_configure(struct pci_dev *pdev) } /* - * vt6421 has problems talking to some drives. The following + * vt6420/1 has problems talking to some drives. The following * is the fix from Joseph Chan . * * When host issues HOLD, device may send up to 20DW of data @@ -596,8 +596,9 @@ static void svia_configure(struct pci_dev *pdev) * * https://bugzilla.kernel.org/show_bug.cgi?id=15173 * http://article.gmane.org/gmane.linux.ide/46352 + * http://thread.gmane.org/gmane.linux.kernel/1062139 */ - if (pdev->device == 0x3249) { + if (board_id == vt6420 || board_id == vt6421) { pci_read_config_byte(pdev, 0x52, &tmp8); tmp8 |= 1 << 2; pci_write_config_byte(pdev, 0x52, tmp8); @@ -652,7 +653,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - svia_configure(pdev); + svia_configure(pdev, board_id); pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, -- cgit v1.2.3 From 33e0d57f5d2f079104611be9f3fccc27ef2c6b24 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 19 Nov 2010 11:54:40 -0800 Subject: Revert "kernel: make /proc/kallsyms mode 400 to reduce ease of attacking" This reverts commit 59365d136d205cc20fe666ca7f89b1c5001b0d5a. It turns out that this can break certain existing user land setups. Quoth Sarah Sharp: "On Wednesday, I updated my branch to commit 460781b from linus' tree, and my box would not boot. klogd segfaulted, which stalled the whole system. At first I thought it actually hung the box, but it continued booting after 5 minutes, and I was able to log in. It dropped back to the text console instead of the graphical bootup display for that period of time. dmesg surprisingly still works. I've bisected the problem down to this commit (commit 59365d136d205cc20fe666ca7f89b1c5001b0d5a) The box is running klogd 1.5.5ubuntu3 (from Jaunty). Yes, I know that's old. I read the bit in the commit about changing the permissions of kallsyms after boot, but if I can't boot that doesn't help." So let's just keep the old default, and encourage distributions to do the "chmod -r /proc/kallsyms" in their bootup scripts. This is not worth a kernel option to change default behavior, since it's so easily done in user space. Reported-and-bisected-by: Sarah Sharp Cc: Marcus Meissner Cc: Tejun Heo Cc: Eugene Teo Cc: Jesper Juhl Signed-off-by: Linus Torvalds --- kernel/kallsyms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index a8db2570f99a..6f6d091b5757 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -546,7 +546,7 @@ static const struct file_operations kallsyms_operations = { static int __init kallsyms_init(void) { - proc_create("kallsyms", 0400, NULL, &kallsyms_operations); + proc_create("kallsyms", 0444, NULL, &kallsyms_operations); return 0; } device_initcall(kallsyms_init); -- cgit v1.2.3 From 93bb41f4f8b89ac8b4d0a734bc59634cb0a29a89 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Fri, 19 Nov 2010 21:18:35 -0500 Subject: fs: Do not dispatch FITRIM through separate super_operation There was concern that FITRIM ioctl is not common enough to be included in core vfs ioctl, as Christoph Hellwig pointed out there's no real point in dispatching this out to a separate vector instead of just through ->ioctl. So this commit removes ioctl_fstrim() from vfs ioctl and trim_fs from super_operation structure. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 1 - fs/ioctl.c | 39 --------------------------------------- include/linux/fs.h | 1 - 3 files changed, 41 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 14ada8c50c43..e32195d6aac3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1197,7 +1197,6 @@ static const struct super_operations ext4_sops = { .quota_write = ext4_quota_write, #endif .bdev_try_to_free_page = bdev_try_to_free_page, - .trim_fs = ext4_trim_fs }; static const struct super_operations ext4_nojournal_sops = { diff --git a/fs/ioctl.c b/fs/ioctl.c index e92fdbb3bc3a..f855ea4fc888 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -530,41 +530,6 @@ static int ioctl_fsthaw(struct file *filp) return thaw_super(sb); } -static int ioctl_fstrim(struct file *filp, void __user *argp) -{ - struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; - struct fstrim_range range; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* If filesystem doesn't support trim feature, return. */ - if (sb->s_op->trim_fs == NULL) - return -EOPNOTSUPP; - - /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ - if (sb->s_bdev == NULL) - return -EINVAL; - - if (argp == NULL) { - range.start = 0; - range.len = ULLONG_MAX; - range.minlen = 0; - } else if (copy_from_user(&range, argp, sizeof(range))) - return -EFAULT; - - ret = sb->s_op->trim_fs(sb, &range); - if (ret < 0) - return ret; - - if ((argp != NULL) && - (copy_to_user(argp, &range, sizeof(range)))) - return -EFAULT; - - return 0; -} - /* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. @@ -615,10 +580,6 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error = ioctl_fsthaw(filp); break; - case FITRIM: - error = ioctl_fstrim(filp, argp); - break; - case FS_IOC_FIEMAP: return ioctl_fiemap(filp, arg); diff --git a/include/linux/fs.h b/include/linux/fs.h index 334d68a17108..eedc00b7b1ee 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1612,7 +1612,6 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); - int (*trim_fs) (struct super_block *, struct fstrim_range *); }; /* -- cgit v1.2.3 From e681c047e47c0abe67bf95857f23814372793cb0 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Fri, 19 Nov 2010 21:47:07 -0500 Subject: ext4: Add EXT4_IOC_TRIM ioctl to handle batched discard Filesystem independent ioctl was rejected as not common enough to be in core vfs ioctl. Since we still need to access to this functionality this commit adds ext4 specific ioctl EXT4_IOC_TRIM to dispatch ext4_trim_fs(). It takes fstrim_range structure as an argument. fstrim_range is definec in the include/linux/fs.h and its definition is as follows. struct fstrim_range { __u64 start; __u64 len; __u64 minlen; } start - first Byte to trim len - number of Bytes to trim from start minlen - minimum extent length to trim, free extents shorter than this number of Bytes will be ignored. This will be rounded up to fs block size. After the FITRIM is done, the number of actually discarded Bytes is stored in fstrim_range.len to give the user better insight on how much storage space has been really released for wear-leveling. Signed-off-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" --- fs/ext4/ioctl.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index bf5ae883b1bd..eb3bc2fe647e 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -331,6 +331,30 @@ mext_out: return err; } + case FITRIM: + { + struct super_block *sb = inode->i_sb; + struct fstrim_range range; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&range, (struct fstrim_range *)arg, + sizeof(range))) + return -EFAULT; + + ret = ext4_trim_fs(sb, &range); + if (ret < 0) + return ret; + + if (copy_to_user((struct fstrim_range *)arg, &range, + sizeof(range))) + return -EFAULT; + + return 0; + } + default: return -ENOTTY; } -- cgit v1.2.3 From 9be4d4575906af9698de660e477f949a076c87e1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 31 Aug 2010 15:01:16 -0700 Subject: xen: add extra pages to balloon Add extra pages in the pseudo-physical address space to the balloon so we can extend into them later. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/balloon.c | 15 +++++++++++---- include/xen/page.h | 7 +++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 500290b150bb..df26ee9caa68 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -119,7 +119,7 @@ static void scrub_page(struct page *page) } /* balloon_append: add the given page to the balloon. */ -static void balloon_append(struct page *page) +static void __balloon_append(struct page *page) { /* Lowmem is re-populated first, so highmem pages go at list tail. */ if (PageHighMem(page)) { @@ -130,7 +130,11 @@ static void balloon_append(struct page *page) list_add(&page->lru, &ballooned_pages); balloon_stats.balloon_low++; } +} +static void balloon_append(struct page *page) +{ + __balloon_append(page); totalram_pages--; } @@ -416,10 +420,13 @@ static int __init balloon_init(void) register_balloon(&balloon_sysdev); /* Initialise the balloon with excess memory space. */ - for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { + for (pfn = PFN_UP(xen_extra_mem_start); + pfn < PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size); + pfn++) { page = pfn_to_page(pfn); - if (!PageReserved(page)) - balloon_append(page); + /* totalram_pages doesn't include the boot-time + balloon extension, so don't subtract from it. */ + __balloon_append(page); } target_watch.callback = watch_target; diff --git a/include/xen/page.h b/include/xen/page.h index eaf85fab1263..0be36b976f4b 100644 --- a/include/xen/page.h +++ b/include/xen/page.h @@ -1 +1,8 @@ +#ifndef _XEN_PAGE_H +#define _XEN_PAGE_H + #include + +extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size; + +#endif /* _XEN_PAGE_H */ -- cgit v1.2.3 From 2f70e0acd496398671606767122846278126a88b Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 2 Sep 2010 23:11:17 -0700 Subject: xen/balloon: the balloon_lock is useless The balloon_lock is useless, since it protects nothing against nothing. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/balloon.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index df26ee9caa68..77b5dc3597e3 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -195,7 +195,7 @@ static unsigned long current_target(void) static int increase_reservation(unsigned long nr_pages) { - unsigned long pfn, i, flags; + unsigned long pfn, i; struct page *page; long rc; struct xen_memory_reservation reservation = { @@ -207,8 +207,6 @@ static int increase_reservation(unsigned long nr_pages) if (nr_pages > ARRAY_SIZE(frame_list)) nr_pages = ARRAY_SIZE(frame_list); - spin_lock_irqsave(&xen_reservation_lock, flags); - page = balloon_first_page(); for (i = 0; i < nr_pages; i++) { BUG_ON(page == NULL); @@ -251,14 +249,12 @@ static int increase_reservation(unsigned long nr_pages) balloon_stats.current_pages += rc; out: - spin_unlock_irqrestore(&xen_reservation_lock, flags); - return rc < 0 ? rc : rc != nr_pages; } static int decrease_reservation(unsigned long nr_pages) { - unsigned long pfn, i, flags; + unsigned long pfn, i; struct page *page; int need_sleep = 0; int ret; @@ -296,8 +292,6 @@ static int decrease_reservation(unsigned long nr_pages) kmap_flush_unused(); flush_tlb_all(); - spin_lock_irqsave(&xen_reservation_lock, flags); - /* No more mappings: invalidate P2M and add to balloon. */ for (i = 0; i < nr_pages; i++) { pfn = mfn_to_pfn(frame_list[i]); @@ -312,8 +306,6 @@ static int decrease_reservation(unsigned long nr_pages) balloon_stats.current_pages -= nr_pages; - spin_unlock_irqrestore(&xen_reservation_lock, flags); - return need_sleep; } -- cgit v1.2.3 From 66946f676776a6ef333db1cf7453ecf8a66c90df Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 14 Sep 2010 10:32:32 -0700 Subject: xen/balloon: make sure we only include remaining extra ram If the user specifies mem= on the kernel command line, some or all of the extra memory E820 region may be clipped away, so make sure we don't try to add more extra memory than exists in E820. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/balloon.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 77b5dc3597e3..2b17ad5b4b32 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -391,7 +392,7 @@ static struct notifier_block xenstore_notifier; static int __init balloon_init(void) { - unsigned long pfn; + unsigned long pfn, extra_pfn_end; struct page *page; if (!xen_pv_domain()) @@ -412,8 +413,10 @@ static int __init balloon_init(void) register_balloon(&balloon_sysdev); /* Initialise the balloon with excess memory space. */ + extra_pfn_end = min(e820_end_of_ram_pfn(), + (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size)); for (pfn = PFN_UP(xen_extra_mem_start); - pfn < PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size); + pfn < extra_pfn_end; pfn++) { page = pfn_to_page(pfn); /* totalram_pages doesn't include the boot-time -- cgit v1.2.3 From d2a817130cdc142f1c80a8e60eca824a321926af Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 19 Nov 2010 23:27:06 -0800 Subject: xen: re-enable boot-time ballooning Now that the balloon driver doesn't stumble over non-RAM pages, we can enable the extra space for ballooning. Signed-off-by: Jeremy Fitzhardinge --- arch/x86/xen/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 769c4b01fa32..630fb53c95f3 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -248,8 +248,7 @@ char * __init xen_memory_setup(void) else extra_pages = 0; - if (!xen_initial_domain()) - xen_add_extra_mem(extra_pages); + xen_add_extra_mem(extra_pages); return "Xen"; } -- cgit v1.2.3 From ab08853fab2093e5c6f5de56827a4c93dce4b055 Mon Sep 17 00:00:00 2001 From: Anupam Chanda Date: Sun, 21 Nov 2010 09:54:21 -0800 Subject: e1000: fix screaming IRQ VMWare reports that the e1000 driver has a bug when bringing down the interface, such that interrupts are not disabled in the hardware but the driver stops reporting that it consumed the interrupt. The fix is to set the driver's "down" flag later in the routine, after all the timers and such have exited, preventing the interrupt handler from being called and exiting early without handling the interrupt. CC: Anupam Chanda CC: stable kernel Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4686c3983fc3..4d62f7bfa036 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -31,7 +31,7 @@ char e1000_driver_name[] = "e1000"; static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -#define DRV_VERSION "7.3.21-k6-NAPI" +#define DRV_VERSION "7.3.21-k8-NAPI" const char e1000_driver_version[] = DRV_VERSION; static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -485,9 +485,6 @@ void e1000_down(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; u32 rctl, tctl; - /* signal that we're down so the interrupt handler does not - * reschedule our watchdog timer */ - set_bit(__E1000_DOWN, &adapter->flags); /* disable receives in the hardware */ rctl = er32(RCTL); @@ -508,6 +505,13 @@ void e1000_down(struct e1000_adapter *adapter) e1000_irq_disable(adapter); + /* + * Setting DOWN must be after irq_disable to prevent + * a screaming interrupt. Setting DOWN also prevents + * timers and tasks from rescheduling. + */ + set_bit(__E1000_DOWN, &adapter->flags); + del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); -- cgit v1.2.3 From a6c36ee677607b02d8ecc88e8a12785418b88107 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Sun, 21 Nov 2010 09:58:04 -0800 Subject: bonding: change list contact to netdev@vger.kernel.org bonding-devel@lists.sourceforge.net seems only receive spam and discussion seems to already occur on netdev@vger.kernel.org. Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8b6ca96435ee..9206cb462913 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1359,7 +1359,7 @@ F: include/net/bluetooth/ BONDING DRIVER M: Jay Vosburgh -L: bonding-devel@lists.sourceforge.net +L: netdev@vger.kernel.org W: http://sourceforge.net/projects/bonding/ S: Supported F: drivers/net/bonding/ -- cgit v1.2.3 From 7a1c8e5ab120a5f352e78bbc1fa5bb64e6f23639 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 20 Nov 2010 07:46:35 +0000 Subject: net: allow GFP_HIGHMEM in __vmalloc() We forgot to use __GFP_HIGHMEM in several __vmalloc() calls. In ceph, add the missing flag. In fib_trie.c, xfrm_hash.c and request_sock.c, using vzalloc() is cleaner and allows using HIGHMEM pages as well. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ceph/buffer.c | 2 +- net/core/request_sock.c | 4 +--- net/ipv4/fib_trie.c | 2 +- net/xfrm/xfrm_hash.c | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/net/ceph/buffer.c b/net/ceph/buffer.c index 53d8abfa25d5..bf3e6a13c215 100644 --- a/net/ceph/buffer.c +++ b/net/ceph/buffer.c @@ -19,7 +19,7 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) if (b->vec.iov_base) { b->is_vmalloc = false; } else { - b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL); + b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL); if (!b->vec.iov_base) { kfree(b); return NULL; diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 7552495aff7a..fceeb37d7161 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -45,9 +45,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); lopt_size += nr_table_entries * sizeof(struct request_sock *); if (lopt_size > PAGE_SIZE) - lopt = __vmalloc(lopt_size, - GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, - PAGE_KERNEL); + lopt = vzalloc(lopt_size); else lopt = kzalloc(lopt_size, GFP_KERNEL); if (lopt == NULL) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 200eb538fbb3..0f280348e0fd 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -365,7 +365,7 @@ static struct tnode *tnode_alloc(size_t size) if (size <= PAGE_SIZE) return kzalloc(size, GFP_KERNEL); else - return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); + return vzalloc(size); } static void __tnode_vfree(struct work_struct *arg) diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c index a2023ec52329..1e98bc0fe0a5 100644 --- a/net/xfrm/xfrm_hash.c +++ b/net/xfrm/xfrm_hash.c @@ -19,7 +19,7 @@ struct hlist_head *xfrm_hash_alloc(unsigned int sz) if (sz <= PAGE_SIZE) n = kzalloc(sz, GFP_KERNEL); else if (hashdist) - n = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); + n = vzalloc(sz); else n = (struct hlist_head *) __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, -- cgit v1.2.3 From 33ac0b84eecaf5e7ee3baa3ef8294e8d8d267cd6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 21 Nov 2010 10:06:48 -0800 Subject: atl1c: Fix hardware type check for enabling OTP CLK Commit 496c185c9495629ef1c65387cb2594578393cfe0 "atl1c: Add support for Atheros AR8152 and AR8152" added the condition: if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) for enabling OTP CLK, and the condition: if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) for disabling OTP CLK. Since the two previously defined hardware types are athr_l1c and athr_l2c, the latter condition appears to be the correct one. Change the former to match. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/atl1c/atl1c_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c index 919080b2c3a5..1bf672009948 100644 --- a/drivers/net/atl1c/atl1c_hw.c +++ b/drivers/net/atl1c/atl1c_hw.c @@ -82,7 +82,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) addr[0] = addr[1] = 0; AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data); if (atl1c_check_eeprom_exist(hw)) { - if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) { + if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { /* Enable OTP CLK */ if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) { otp_ctrl_data |= OTP_CTRL_CLK_EN; -- cgit v1.2.3 From ddab1a3b30452bf6d2a2780dbb5fd962a85bec48 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Thu, 18 Nov 2010 14:24:02 +0000 Subject: SuperH IrDA: correct Baud rate error correction It looks to me as if the second value of rate_err_array is intended to be a decimal 625. However, with a leading 0 it becomes an octal constant, and as such evaluates to a decimal 405. Signed-off-by: Nicolas Kaiser Signed-off-by: David S. Miller --- drivers/net/irda/sh_sir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c index 00b38bccd6d0..52a7c86af663 100644 --- a/drivers/net/irda/sh_sir.c +++ b/drivers/net/irda/sh_sir.c @@ -258,7 +258,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) /* Baud Rate Error Correction x 10000 */ u32 rate_err_array[] = { - 0000, 0625, 1250, 1875, + 0, 625, 1250, 1875, 2500, 3125, 3750, 4375, 5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375, -- cgit v1.2.3 From 3561d43fd289f590fdae672e5eb831b8d5cf0bf6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 21 Nov 2010 15:18:56 -0800 Subject: Linux 2.6.37-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ab5359db3d17..b31d21377e4c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 37 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v1.2.3 From 0613a59456980161d0cd468bae6c63d772743102 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Mon, 1 Nov 2010 01:14:51 -0400 Subject: ALSA: ac97: Apply quirk for Dell Latitude D610 binding Master and Headphone controls BugLink: https://launchpad.net/bugs/669279 The original reporter states: "The Master mixer does not change the volume from the headphone output (which is affected by the headphone mixer). Instead it only seems to control the on-board speaker volume. This confuses PulseAudio greatly as the Master channel is merged into the volume mix." Fix this symptom by applying the hp_only quirk for the reporter's SSID. The fix is applicable to all stable kernels. Reported-and-tested-by: Ben Gamari Cc: [2.6.32+] Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 400f9ebd243e..629a5494347a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1864,6 +1864,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "Dell Inspiron 8600", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x1028, + .subdevice = 0x0182, + .name = "Dell Latitude D610", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, { .subvendor = 0x1028, .subdevice = 0x0186, -- cgit v1.2.3 From 2fb50f135adba59edf2359effcce83eb17025793 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 12 Nov 2010 13:38:04 -0800 Subject: ALSA: sound/ppc: Use printf extension %pR for struct resource Using %pR standardizes the struct resource output. Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/ppc/pmac.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 85081172403f..b47cfd45b3b9 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1228,10 +1228,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " - " %d (%s: 0x%016llx:%016llx)\n", - i, rnames[i], - (unsigned long long)chip->rsrc[i].start, - (unsigned long long)chip->rsrc[i].end); + " %d (%s: %pR)\n", + i, rnames[i], &chip->rsrc[i]); err = -ENODEV; goto __error; } @@ -1256,10 +1254,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " - " %d (%s: 0x%016llx:%016llx)\n", - i, rnames[i], - (unsigned long long)chip->rsrc[i].start, - (unsigned long long)chip->rsrc[i].end); + " %d (%s: %pR)\n", + i, rnames[i], &chip->rsrc[i]); err = -ENODEV; goto __error; } -- cgit v1.2.3 From c80c1d542744dd7851cc8da748c6ada99680fb4d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 19:05:02 -0800 Subject: ALSA: sound/core/pcm_lib.c: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a1707cca9c66..b75db8e9cc0f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -223,7 +223,7 @@ static void xrun_log(struct snd_pcm_substream *substream, entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; - entry->buffer_size = runtime->buffer_size;; + entry->buffer_size = runtime->buffer_size; entry->old_hw_ptr = runtime->status->hw_ptr; entry->hw_ptr_base = runtime->hw_ptr_base; log->idx = (log->idx + 1) % XRUN_LOG_CNT; -- cgit v1.2.3 From 5dbea6b1f2113f764999b39fd3d79b1354c193d9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 15 Nov 2010 12:14:02 -0800 Subject: ALSA: sound/pci/asihpi/hpioctl.c: Remove unnecessary casts of pci_get_drvdata Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 62895a719fcb..22dbd91811a4 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -435,7 +435,7 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) struct hpi_message hm; struct hpi_response hr; struct hpi_adapter *pa; - pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev); + pa = pci_get_drvdata(pci_dev); hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DELETE_ADAPTER); -- cgit v1.2.3 From a0e90acc657990511c83bc69965bfd3c63386d45 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sat, 20 Nov 2010 10:20:35 -0500 Subject: ALSA: hda: Add Samsung R720 SSID for subwoofer pin fixup BugLink: https://launchpad.net/bugs/677830 The original reporter states that the subwoofer does not mute when inserting headphones. We need an entry for his machine's SSID in the subwoofer pin fixup list, so add it there (verified using hda_analyzer). Reported-and-tested-by: i-NoD Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5f00589cb791..1a7703a49655 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19298,6 +19298,7 @@ static const struct alc_fixup alc662_fixups[] = { static struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), {} -- cgit v1.2.3 From 78ac07b0d2b09b1ccb7a41a2e25f71d60b652920 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 21 Nov 2010 12:09:32 +0100 Subject: ALSA: azt3328: period bug fix (for PA), add missing ACK on stop timer . Fix PulseAudio "ALSA driver bug" issue (if we have two alternated areas within a 64k DMA buffer, then max period size should obviously be 32k only). Back references: http://pulseaudio.org/wiki/AlsaIssues http://fedoraproject.org/wiki/Features/GlitchFreeAudio . In stop timer function, need to supply ACK in the timer control byte. . Minor log output correction When I did my first PA testing recently, the period size bug resulted in quite precisely observeable half-period-based playback distortion. PA-based operation is quite a bit more underrun-prone (despite its zero-copy optimizations etc.) than raw ALSA with this rather spartan sound hardware implementation on my puny Athlon. Note that even with this patch, azt3328 still doesn't work for both cases yet, PA tsched=0 and tsched (on tsched=0 it will playback tiny fragments of periods, leading to tiny stuttering sounds with some pauses in between, whereas with timer-scheduled operation playback works fine - minus some quite increased underrun trouble on PA vs. ALSA, that is). Signed-off-by: Andreas Mohr Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 4679ed83a43b..2f3cacbd5528 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1129,10 +1129,11 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, count_areas = size/2; addr_area2 = addr+count_areas; - count_areas--; /* max. index */ snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", addr, count_areas, addr_area2, count_areas); + count_areas--; /* max. index */ + /* build combined I/O buffer length word */ lengths = (count_areas << 16) | (count_areas); spin_lock_irqsave(&chip->reg_lock, flags); @@ -1740,11 +1741,15 @@ static const struct snd_pcm_hardware snd_azf3328_hardware = .rate_max = AZF_FREQ_66200, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = 65536, - .period_bytes_min = 64, - .period_bytes_max = 65536, - .periods_min = 1, - .periods_max = 1024, + .buffer_bytes_max = (64*1024), + .period_bytes_min = 1024, + .period_bytes_max = (32*1024), + /* We simply have two DMA areas (instead of a list of descriptors + such as other cards); I believe that this is a fixed hardware + attribute and there isn't much driver magic to be done to expand it. + Thus indicate that we have at least and at most 2 periods. */ + .periods_min = 2, + .periods_max = 2, /* FIXME: maybe that card actually has a FIFO? * Hmm, it seems newer revisions do have one, but we still don't know * its size... */ @@ -1980,8 +1985,13 @@ snd_azf3328_timer_stop(struct snd_timer *timer) chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->reg_lock, flags); /* disable timer countdown and interrupt */ - /* FIXME: should we write TIMER_IRQ_ACK here? */ - snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); + /* Hmm, should we write TIMER_IRQ_ACK here? + YES indeed, otherwise a rogue timer operation - which prompts + ALSA(?) to call repeated stop() in vain, but NOT start() - + will never end (value 0x03 is kept shown in control byte). + Simply manually poking 0x04 _once_ immediately successfully stops + the hardware/ALSA interrupt activity. */ + snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); return 0; -- cgit v1.2.3 From c0763e687d0283d0db507813ca4462aa4073c5b5 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 21 Nov 2010 20:40:07 +0300 Subject: ALSA: snd-atmel-abdac: test wrong variable After clk_get() pclk is checked second time instead of sample_clk check. Signed-off-by: Vasiliy Kulikov Signed-off-by: Takashi Iwai --- sound/atmel/abdac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index f2f41c854221..4e47baada66f 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -420,7 +420,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev) return PTR_ERR(pclk); } sample_clk = clk_get(&pdev->dev, "sample_clk"); - if (IS_ERR(pclk)) { + if (IS_ERR(sample_clk)) { dev_dbg(&pdev->dev, "no sample clock\n"); retval = PTR_ERR(pclk); goto out_put_pclk; -- cgit v1.2.3 From 673f7a8984c3a9e2cb1108ce221da1ebbd9e5d09 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 21 Nov 2010 14:01:14 -0500 Subject: ALSA: hda: Use hp-laptop quirk to enable headphones automute for Asus A52J BugLink: https://launchpad.net/bugs/677652 The original reporter states that, in 2.6.35, headphones do not appear to work, nor does inserting them mute the A52J's onboard speakers. Upon inspecting the codec dump, it appears that the newly committed hp-laptop quirk will suffice to enable this basic functionality. Testing was done with an alsa-driver build from 2010-11-21. Reported-and-tested-by: Joan Creus Cc: [2.6.35+] Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6361f752b5f3..3cfb31e77b16 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3100,6 +3100,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), -- cgit v1.2.3 From 1beded5d9ce90256e4a7e7b0e96c317eafe1c513 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 Nov 2010 08:58:13 +0100 Subject: ALSA: atmel - Fix the return value in error path In the commit c0763e687d0283d0db507813ca4462aa4073c5b5 ALSA: snd-atmel-abdac: test wrong variable the return value via PTR_ERR() had to be fixed as well. Signed-off-by: Takashi Iwai --- sound/atmel/abdac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 4e47baada66f..6e2409181895 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -422,7 +422,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev) sample_clk = clk_get(&pdev->dev, "sample_clk"); if (IS_ERR(sample_clk)) { dev_dbg(&pdev->dev, "no sample clock\n"); - retval = PTR_ERR(pclk); + retval = PTR_ERR(sample_clk); goto out_put_pclk; } clk_enable(pclk); -- cgit v1.2.3 From 01e0f1378c47947b825eac05c98697ab1be1c86f Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Mon, 22 Nov 2010 10:59:36 +0100 Subject: ALSA: hda - Fixed ALC887-VD initial error ALC887-VD is like ALC888-VD. It can not be initialized as ALC882. Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1a7703a49655..564e6c136ddd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19420,7 +19420,10 @@ static int patch_alc888(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){ kfree(codec->chip_name); - codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); + if (codec->vendor_id == 0x10ec0887) + codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL); + else + codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); if (!codec->chip_name) { alc_free(codec); return -ENOMEM; @@ -19910,7 +19913,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", .patch = patch_alc882 }, { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc882 }, { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, -- cgit v1.2.3 From 88b2a9a3d98a19496d64aadda7158c0ad51cbe7d Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 15 Nov 2010 20:29:21 +0000 Subject: ipv6: fix missing in6_ifa_put in addrconf Fix ref count bug introduced by commit 2de795707294972f6c34bae9de713e502c431296 Author: Lorenzo Colitti Date: Wed Oct 27 18:16:49 2010 +0000 ipv6: addrconf: don't remove address state on ifdown if the address is being kept Fix logic so that addrconf_ifdown() decrements the inet6_ifaddr refcnt correctly with in6_ifa_put(). Reported-by: Stephen Hemminger Signed-off-by: John Fastabend Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2fc35b32df9e..23cc8e1ce8d4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2758,13 +2758,13 @@ static int addrconf_ifdown(struct net_device *dev, int how) ifa->state = INET6_IFADDR_STATE_DEAD; spin_unlock_bh(&ifa->state_lock); - if (state == INET6_IFADDR_STATE_DEAD) { - in6_ifa_put(ifa); - } else { + if (state != INET6_IFADDR_STATE_DEAD) { __ipv6_ifa_notify(RTM_DELADDR, ifa); atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); } + + in6_ifa_put(ifa); write_lock_bh(&idev->lock); } } -- cgit v1.2.3 From 84cf7029b63ca3eef823438a29ceb5ba139b883a Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 18 Nov 2010 11:50:02 +0000 Subject: qlge: Fix incorrect usage of module parameters and netdev msg level Driver appears to be mistaking the permission field with default value in the case of debug and qlge_irq_type. Driver is also passing debug as a bitmask into netif_msg_init() which wants a number of bits. Ron Mercer suggests we should change this to pass in -1 so the defaults get used instead, which makes the default much less verbose. Signed-off-by: Milton Miller Signed-off-by: Sonny Rao Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c30e0fe55a31..528eaef5308f 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -62,15 +62,15 @@ static const u32 default_msg = /* NETIF_MSG_PKTDATA | */ NETIF_MSG_HW | NETIF_MSG_WOL | 0; -static int debug = 0x00007fff; /* defaults above */ -module_param(debug, int, 0); +static int debug = -1; /* defaults above */ +module_param(debug, int, 0664); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); #define MSIX_IRQ 0 #define MSI_IRQ 1 #define LEG_IRQ 2 static int qlge_irq_type = MSIX_IRQ; -module_param(qlge_irq_type, int, MSIX_IRQ); +module_param(qlge_irq_type, int, 0664); MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); static int qlge_mpi_coredump; -- cgit v1.2.3 From 27d916d680e7b324087a75d080f215e7c34a4e8f Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 19 Nov 2010 11:58:52 +0000 Subject: phylib: Use common page register definition for Marvell PHYs. The definition of the Marvell PHY page register is not specific to 88E1121, so rename the macro to MII_MARVELL_PHY_PAGE, and use it throughout. Suggested-by: Cyril Chemparathy Signed-off-by: David Daney Cc: Cyril Chemparathy Cc: Arnaud Patard Cc: Benjamin Herrenschmidt Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f0bd1a1aba3a..3600b8b21bf2 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -35,6 +35,8 @@ #include #include +#define MII_MARVELL_PHY_PAGE 22 + #define MII_M1011_IEVENT 0x13 #define MII_M1011_IEVENT_CLEAR 0x0000 @@ -80,7 +82,6 @@ #define MII_88E1121_PHY_LED_CTRL 16 #define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 -#define MII_88E1121_PHY_PAGE 22 #define MII_M1011_PHY_STATUS 0x11 #define MII_M1011_PHY_STATUS_1000 0x8000 @@ -190,9 +191,9 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_88E1121_PHY_PAGE, + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -218,7 +219,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -229,11 +230,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (err < 0) return err; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); + phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); - phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); err = genphy_config_aneg(phydev); @@ -244,9 +245,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_88E1121_PHY_PAGE, + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -258,7 +259,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); if (err < 0) return err; @@ -398,7 +399,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, 0x16, 0x0002); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); if (err < 0) return err; @@ -408,7 +409,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = phy_write(phydev, 0x16, 0x0003); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); if (err < 0) return err; @@ -421,7 +422,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, 0x16, 0x0); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); if (err < 0) return err; -- cgit v1.2.3 From 90600732d8b2fbc422bc9c57bdc73513d909367f Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 19 Nov 2010 11:58:53 +0000 Subject: phylib: Add support for Marvell 88E1149R devices. The 88E1149R is 10/100/1000 quad-gigabit Ethernet PHY. The .config_aneg function can be shared with 88E1118, but it needs its own .config_init. Signed-off-by: David Daney Cc: Cyril Chemparathy Cc: Arnaud Patard Cc: Benjamin Herrenschmidt Cc: Wolfram Sang Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/marvell_phy.h | 1 + 2 files changed, 41 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 3600b8b21bf2..def19d7c53ef 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -433,6 +433,32 @@ static int m88e1118_config_init(struct phy_device *phydev) return 0; } +static int m88e1149_config_init(struct phy_device *phydev) +{ + int err; + + /* Change address */ + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + if (err < 0) + return err; + + /* Enable 1000 Mbit */ + err = phy_write(phydev, 0x15, 0x1048); + if (err < 0) + return err; + + /* Reset address */ + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + if (err < 0) + return err; + + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + return 0; +} + static int m88e1145_config_init(struct phy_device *phydev) { int err; @@ -685,6 +711,19 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .driver = { .owner = THIS_MODULE }, }, + { + .phy_id = MARVELL_PHY_ID_88E1149R, + .phy_id_mask = MARVELL_PHY_ID_MASK, + .name = "Marvell 88E1149R", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &m88e1149_config_init, + .config_aneg = &m88e1118_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = { .owner = THIS_MODULE }, + }, { .phy_id = MARVELL_PHY_ID_88E1240, .phy_id_mask = MARVELL_PHY_ID_MASK, @@ -736,6 +775,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = { { 0x01410e10, 0xfffffff0 }, { 0x01410cb0, 0xfffffff0 }, { 0x01410cd0, 0xfffffff0 }, + { 0x01410e50, 0xfffffff0 }, { 0x01410e30, 0xfffffff0 }, { 0x01410e90, 0xfffffff0 }, { } diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h index 1ff81b51b656..dd3c34ebca9a 100644 --- a/include/linux/marvell_phy.h +++ b/include/linux/marvell_phy.h @@ -11,6 +11,7 @@ #define MARVELL_PHY_ID_88E1118 0x01410e10 #define MARVELL_PHY_ID_88E1121R 0x01410cb0 #define MARVELL_PHY_ID_88E1145 0x01410cd0 +#define MARVELL_PHY_ID_88E1149R 0x01410e50 #define MARVELL_PHY_ID_88E1240 0x01410e30 #define MARVELL_PHY_ID_88E1318S 0x01410e90 -- cgit v1.2.3 From cf41a51db89850033efc11c18a5257de810b5417 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 19 Nov 2010 12:13:18 +0000 Subject: of/phylib: Use device tree properties to initialize Marvell PHYs. Some aspects of PHY initialization are board dependent, things like indicator LED connections and some clocking modes cannot be determined by probing. The dev_flags element of struct phy_device can be used to control these things if an appropriate value can be passed from the Ethernet driver. We run into problems however if the PHY connections are specified by the device tree. There is no way for the Ethernet driver to know what flags it should pass. If we are using the device tree, the struct phy_device will be populated with the device tree node corresponding to the PHY, and we can extract extra configuration information from there. The next question is what should the format of that information be? It is highly device specific, and the device tree representation should not be tied to any arbitrary kernel defined constants. A straight forward representation is just to specify the exact bits that should be set using the "marvell,reg-init" property: phy5: ethernet-phy@5 { reg = <5>; compatible = "marvell,88e1149r"; marvell,reg-init = /* led[0]:1000, led[1]:100, led[2]:10, led[3]:tx */ <3 0x10 0 0x5777>, /* Reg 3,16 <- 0x5777 */ /* mix %:0, led[0123]:drive low off hiZ */ <3 0x11 0 0x00aa>, /* Reg 3,17 <- 0x00aa */ /* default blink periods. */ <3 0x12 0 0x4105>, /* Reg 3,18 <- 0x4105 */ /* led[4]:rx, led[5]:dplx, led[45]:drive low off hiZ */ <3 0x13 0 0x0a60>; /* Reg 3,19 <- 0x0a60 */ }; phy6: ethernet-phy@6 { reg = <6>; compatible = "marvell,88e1118"; marvell,reg-init = /* Fix rx and tx clock transition timing */ <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ /* Adjust LED drive. */ <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ /* irq, blink-activity, blink-link */ <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ }; The Marvell PHYs have a page select register at register 22 (0x16), we can specify any register by its page and register number. These are the first and second word. The third word contains a mask to be ANDed with the existing register value, and the fourth word is ORed with the result to yield the new register value. The new marvell_of_reg_init function leaves the page select register unchanged, so a call to it can be dropped into the .config_init functions without unduly affecting the state of the PHY. If CONFIG_OF_MDIO is not set, there is no of_node, or no "marvell,reg-init" property, the PHY initialization is unchanged. Signed-off-by: David Daney Cc: Grant Likely Cc: Cyril Chemparathy Cc: David Daney Cc: Arnaud Patard Cc: Benjamin Herrenschmidt Reviewed-by: Grant Likely Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index def19d7c53ef..e8b9c53c304b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -187,6 +188,87 @@ static int marvell_config_aneg(struct phy_device *phydev) return 0; } +#ifdef CONFIG_OF_MDIO +/* + * Set and/or override some configuration registers based on the + * marvell,reg-init property stored in the of_node for the phydev. + * + * marvell,reg-init = ,...; + * + * There may be one or more sets of : + * + * reg-page: which register bank to use. + * reg: the register. + * mask: if non-zero, ANDed with existing register value. + * value: ORed with the masked value and written to the regiser. + * + */ +static int marvell_of_reg_init(struct phy_device *phydev) +{ + const __be32 *paddr; + int len, i, saved_page, current_page, page_changed, ret; + + if (!phydev->dev.of_node) + return 0; + + paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len); + if (!paddr || len < (4 * sizeof(*paddr))) + return 0; + + saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); + if (saved_page < 0) + return saved_page; + page_changed = 0; + current_page = saved_page; + + ret = 0; + len /= sizeof(*paddr); + for (i = 0; i < len - 3; i += 4) { + u16 reg_page = be32_to_cpup(paddr + i); + u16 reg = be32_to_cpup(paddr + i + 1); + u16 mask = be32_to_cpup(paddr + i + 2); + u16 val_bits = be32_to_cpup(paddr + i + 3); + int val; + + if (reg_page != current_page) { + current_page = reg_page; + page_changed = 1; + ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); + if (ret < 0) + goto err; + } + + val = 0; + if (mask) { + val = phy_read(phydev, reg); + if (val < 0) { + ret = val; + goto err; + } + val &= mask; + } + val |= val_bits; + + ret = phy_write(phydev, reg, val); + if (ret < 0) + goto err; + + } +err: + if (page_changed) { + i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); + if (ret == 0) + ret = i; + } + return ret; +} +#else +static int marvell_of_reg_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_OF_MDIO */ + static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; @@ -369,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev) return err; } + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -421,6 +506,10 @@ static int m88e1118_config_init(struct phy_device *phydev) if (err < 0) return err; + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + /* Reset address */ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); if (err < 0) @@ -447,6 +536,10 @@ static int m88e1149_config_init(struct phy_device *phydev) if (err < 0) return err; + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + /* Reset address */ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); if (err < 0) @@ -518,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev) } } + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + return 0; } -- cgit v1.2.3 From ec35a69c467026437519bafcf325a7362e422db9 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 16 Nov 2010 12:09:59 -0500 Subject: xen: set IO permission early (before early_cpu_init()) This patch is based off "xen dom0: Set up basic IO permissions for dom0." by Juan Quintela . On AMD machines when we boot the kernel as Domain 0 we get this nasty: mapping kernel into physical memory Xen: setup ISA identity maps about to get started... (XEN) traps.c:475:d0 Unhandled general protection fault fault/trap [#13] on VCPU 0 [ec=0000] (XEN) domain_crash_sync called from entry.S (XEN) Domain 0 (vcpu#0) crashed on cpu#0: (XEN) ----[ Xen-4.1-101116 x86_64 debug=y Not tainted ]---- (XEN) CPU: 0 (XEN) RIP: e033:[] (XEN) RFLAGS: 0000000000000282 EM: 1 CONTEXT: pv guest (XEN) rax: 000000008000c068 rbx: ffffffff8186c680 rcx: 0000000000000068 (XEN) rdx: 0000000000000cf8 rsi: 000000000000c000 rdi: 0000000000000000 (XEN) rbp: ffffffff81801e98 rsp: ffffffff81801e50 r8: ffffffff81801eac (XEN) r9: ffffffff81801ea8 r10: ffffffff81801eb4 r11: 00000000ffffffff (XEN) r12: ffffffff8186c694 r13: ffffffff81801f90 r14: ffffffffffffffff (XEN) r15: 0000000000000000 cr0: 000000008005003b cr4: 00000000000006f0 (XEN) cr3: 0000000221803000 cr2: 0000000000000000 (XEN) ds: 0000 es: 0000 fs: 0000 gs: 0000 ss: e02b cs: e033 (XEN) Guest stack trace from rsp=ffffffff81801e50: RIP points to read_pci_config() function. The issue is that we don't set IO permissions for the Linux kernel early enough. The call sequence used to be: xen_start_kernel() x86_init.oem.arch_setup = xen_setup_arch; setup_arch: - early_cpu_init - early_init_amd - read_pci_config - x86_init.oem.arch_setup [ xen_arch_setup ] - set IO permissions. We need to set the IO permissions earlier on, which this patch does. Acked-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/xen/enlighten.c | 12 +++++++++++- arch/x86/xen/setup.c | 8 -------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bd3554934613..7250bef7f49e 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1095,6 +1095,8 @@ static void __init xen_setup_stackprotector(void) /* First C function to be called on Xen boot */ asmlinkage void __init xen_start_kernel(void) { + struct physdev_set_iopl set_iopl; + int rc; pgd_t *pgd; if (!xen_start_info) @@ -1209,10 +1211,18 @@ asmlinkage void __init xen_start_kernel(void) #else pv_info.kernel_rpl = 0; #endif - /* set the limit of our address space */ xen_reserve_top(); + /* We used to do this in xen_arch_setup, but that is too late on AMD + * were early_cpu_init (run before ->arch_setup()) calls early_amd_init + * which pokes 0xcf8 port. + */ + set_iopl.iopl = 1; + rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); + if (rc != 0) + xen_raw_printk("physdev_op failed %d\n", rc); + #ifdef CONFIG_X86_32 /* set up basic CPUID stuff */ cpu_detect(&new_cpu_data); diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 630fb53c95f3..38fdffaa71d3 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -336,9 +336,6 @@ void __cpuinit xen_enable_syscall(void) void __init xen_arch_setup(void) { - struct physdev_set_iopl set_iopl; - int rc; - xen_panic_handler_init(); HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); @@ -355,11 +352,6 @@ void __init xen_arch_setup(void) xen_enable_sysenter(); xen_enable_syscall(); - set_iopl.iopl = 1; - rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); - if (rc != 0) - printk(KERN_INFO "physdev_op failed %d\n", rc); - #ifdef CONFIG_ACPI if (!(xen_start_info->flags & SIF_INITDOMAIN)) { printk(KERN_INFO "ACPI in unprivileged domain disabled\n"); -- cgit v1.2.3 From 12334715720b012180579f57650879d0fbb11a84 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 19 Nov 2010 11:27:09 -0500 Subject: xen/events: Use PIRQ instead of GSI value when unmapping MSI/MSI-X irqs. When we allocate a vector for MSI/MSI-X we save away the PIRQ, and the vector value. When we unmap (de-allocate) the MSI/MSI-X vector(s) we need to provide the PIRQ and the vector value. What we did instead was to provide the GSI (which was zero) and the vector value, and we got these unhappy error messages: (XEN) irq.c:1575: dom0: pirq 0 not mapped [ 7.733415] unmap irq failed -22 This patches fixes this and we use the PIRQ value instead of the GSI value. CC: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d6d4f76ed500..2811bb988ea0 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -755,7 +755,7 @@ int xen_destroy_irq(int irq) goto out; if (xen_initial_domain()) { - unmap_irq.pirq = info->u.pirq.gsi; + unmap_irq.pirq = info->u.pirq.pirq; unmap_irq.domid = DOMID_SELF; rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); if (rc) { -- cgit v1.2.3 From d090f5976dfcac4935286676825d64e081335e09 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Nov 2010 07:39:58 +0100 Subject: ALSA: Revert "ALSA: hda - Fix switching between dmic and mic using the same mux on IDT/STAC" This reverts commit f41cc2a85d52ac6971299922084ac5ac59dc339d. The patch broke the digital mic pin handling wrongly. Reference: bko#23162 https://bugzilla.kernel.org/show_bug.cgi?id=23162 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index cfd73afad882..5c710807dfe5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3491,10 +3491,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, return err; } - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) snd_hda_add_imux_item(imux, label, index, NULL); - spec->num_analog_muxes++; - } } return 0; -- cgit v1.2.3 From 6027277e77df2d2893d906c42f5c9f9abcb731e0 Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Tue, 23 Nov 2010 07:43:44 +0100 Subject: ALSA: hda - Enable jack sense for Thinkpad Edge 11 Add a quirk entry for Thinkpad Edge 11 as well as other TP Edge models. Signed-off-by: Manoj Iyer Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3cfb31e77b16..846d1ead47fd 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3111,6 +3111,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), -- cgit v1.2.3 From 1657cbd87125a623d28ce8a7ef5ff6959098d425 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 23 Nov 2010 08:53:32 +0100 Subject: ALSA: hda - Fix wrong ALC269 variant check The refactoring commit d433a67831ab2c470cc53a3ff9b60f656767be15 ALSA: hda - Optimize the check of ALC269 codec variants introduced a wrong check for ALC269-vb type. This patch corrects it. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 564e6c136ddd..38b63fb79cbd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -15104,7 +15104,7 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_digital_capture = &alc269_pcm_digital_capture; if (!spec->adc_nids) { /* wasn't filled automatically? use default */ - if (spec->codec_variant != ALC269_TYPE_NORMAL) { + if (spec->codec_variant == ALC269_TYPE_NORMAL) { spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; -- cgit v1.2.3 From 48c88e820fb3e35c5925e4743fd13f200891b7b5 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 23 Nov 2010 08:56:16 +0100 Subject: ALSA: hda - Identify more variants for ALC269 Give more correct chip names for ALC269-variant codecs. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 38b63fb79cbd..0ac6aed0c889 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14623,7 +14623,10 @@ static int alc275_setup_dual_adc(struct hda_codec *codec) /* different alc269-variants */ enum { ALC269_TYPE_NORMAL, + ALC269_TYPE_ALC258, ALC269_TYPE_ALC259, + ALC269_TYPE_ALC269VB, + ALC269_TYPE_ALC270, ALC269_TYPE_ALC271X, }; @@ -15023,7 +15026,7 @@ static int alc269_fill_coef(struct hda_codec *codec) static int patch_alc269(struct hda_codec *codec) { struct alc_spec *spec; - int board_config; + int board_config, coef; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -15034,14 +15037,23 @@ static int patch_alc269(struct hda_codec *codec) alc_auto_parse_customize_define(codec); - if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { if (codec->bus->pci->subsystem_vendor == 0x1025 && spec->cdefine.platform_type == 1) { alc_codec_rename(codec, "ALC271X"); spec->codec_variant = ALC269_TYPE_ALC271X; - } else { + } else if ((coef & 0xf000) == 0x1000) { + spec->codec_variant = ALC269_TYPE_ALC270; + } else if ((coef & 0xf000) == 0x2000) { alc_codec_rename(codec, "ALC259"); spec->codec_variant = ALC269_TYPE_ALC259; + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + spec->codec_variant = ALC269_TYPE_ALC258; + } else { + alc_codec_rename(codec, "ALC269VB"); + spec->codec_variant = ALC269_TYPE_ALC269VB; } } else alc_fix_pll_init(codec, 0x20, 0x04, 15); -- cgit v1.2.3 From e8ee13a818db4954517cea7da6e7c15b9656eb00 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:22:58 +0000 Subject: ARM: mach-shmobile: clock-sh7372: remove fsidiv bogus disable Current FSIDIV clock framework had bogus disable. This patch remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7db31e6c6bf2..13226323e4e0 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -453,10 +453,8 @@ static int fsidiv_enable(struct clk *clk) unsigned long value; value = __raw_readl(clk->mapping->base) >> 16; - if (value < 2) { - fsidiv_disable(clk); + if (value < 2) return -ENOENT; - } __raw_writel((value << 16) | 0x3, clk->mapping->base); @@ -468,11 +466,6 @@ static int fsidiv_set_rate(struct clk *clk, { int idx; - if (clk->parent->rate == rate) { - fsidiv_disable(clk); - return 0; - } - idx = (clk->parent->rate / rate) & 0xffff; if (idx < 2) return -ENOENT; -- cgit v1.2.3 From d4bc99b977e3a1dd10a84a01ebe59ac2ccebf0cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 24 Nov 2010 02:44:06 +0000 Subject: ARM: mach-shmobile: ap4evb: FSI clock use proper process for HDMI Current AP4 FSI set_rate function used bogus clock process which didn't care enable/disable and clk->usecound. To solve this issue, this patch also modify FSI driver to call set_rate with enough options. This patch modify it. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 58 +++++++++++++++++++++++++++-------- arch/arm/mach-shmobile/clock-sh7372.c | 2 +- include/sound/sh_fsi.h | 6 ++-- sound/soc/sh/fsi.c | 19 ++++++++++-- 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d3260542b943..61c1068198ec 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -567,40 +567,72 @@ static struct platform_device *qhd_devices[] __initdata = { /* FSI */ #define IRQ_FSI evt2irq(0x1840) +static int __fsi_set_rate(struct clk *clk, long rate, int enable) +{ + int ret = 0; + + if (rate <= 0) + return ret; -static int fsi_set_rate(int is_porta, int rate) + if (enable) { + ret = clk_set_rate(clk, clk_round_rate(clk, rate)); + if (0 == ret) + ret = clk_enable(clk); + } else { + clk_disable(clk); + } + + return ret; +} + +static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; + long fsib_rate = 0; + long fdiv_rate = 0; + int ackmd_bpfmd; int ret; /* set_rate is not needed if port A */ if (is_porta) return 0; - fsib_clk = clk_get(NULL, "fsib_clk"); - if (IS_ERR(fsib_clk)) - return -EINVAL; - switch (rate) { case 44100: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; case 48000: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000)); - clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = 85428000; /* around 48kHz x 256 x 7 */ + fdiv_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; default: pr_err("unsupported rate in FSI2 port B\n"); - ret = -EINVAL; - break; + return -EINVAL; } + /* FSI B setting */ + fsib_clk = clk_get(dev, "ickb"); + if (IS_ERR(fsib_clk)) + return -EIO; + + ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); + if (ret < 0) + return ret; - return ret; + /* FSI DIV setting */ + ret = __fsi_set_rate(fdiv_clk, fdiv_rate, enable); + if (ret < 0) { + /* disable FSI B */ + if (enable) + __fsi_set_rate(fsib_clk, fsib_rate, 0); + return ret; + } + + return ackmd_bpfmd; } static struct sh_fsi_platform_info fsi_info = { diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 13226323e4e0..4191e2921127 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -471,7 +471,7 @@ static int fsidiv_set_rate(struct clk *clk, return -ENOENT; __raw_writel(idx << 16, clk->mapping->base); - return fsidiv_enable(clk); + return 0; } static struct clk_ops fsidiv_clk_ops = { diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index fa60cbda90a4..d79894192ae3 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -85,7 +85,9 @@ * ACK_MD (FSI2) * CKG1 (FSI) * - * err: return value < 0 + * err : return value < 0 + * no change : return value == 0 + * change xMD : return value > 0 * * 0x-00000AB * @@ -111,7 +113,7 @@ struct sh_fsi_platform_info { unsigned long porta_flags; unsigned long portb_flags; - int (*set_rate)(int is_porta, int rate); /* for master mode */ + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); }; #endif /* __SOUND_FSI_H */ diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 507e709f2807..136414f163e9 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -132,6 +132,8 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; + long rate; + u32 mst_ctrl; }; @@ -854,10 +856,17 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = fsi_is_play(substream); + struct fsi_master *master = fsi_get_master(fsi); + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); fsi_irq_disable(fsi, is_play); fsi_clk_ctrl(fsi, 0); + set_rate = master->info->set_rate; + if (set_rate && fsi->rate) + set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); + fsi->rate = 0; + pm_runtime_put_sync(dai->dev); } @@ -891,9 +900,10 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_master *master = fsi_get_master(fsi); - int (*set_rate)(int is_porta, int rate) = master->info->set_rate; + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); int fsi_ver = master->core->ver; int is_play = fsi_is_play(substream); + long rate = params_rate(params); int ret; /* if slave mode, set_rate is not needed */ @@ -901,10 +911,15 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, return 0; /* it is error if no set_rate */ + set_rate = master->info->set_rate; if (!set_rate) return -EIO; - ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); + ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); + if (ret < 0) /* error */ + return ret; + + fsi->rate = rate; if (ret > 0) { u32 data = 0; -- cgit v1.2.3 From 22de4e1fe446794acaebdf19dcaff4256d659972 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:17 +0000 Subject: ARM: mach-shmobile: ap4evb: FSI clock use proper process for ak4642 Current AP4 FSI didn't use set_rate for ak4642, and used dummy rate when init. And FSI driver was modified to always call set_rate. The user which are using FSI set_rate is only AP4 now. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 96 ++++++++++++++++++++++++----------- sound/soc/sh/fsi.c | 8 +-- 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 61c1068198ec..e084b423146e 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -575,7 +575,7 @@ static int __fsi_set_rate(struct clk *clk, long rate, int enable) return ret; if (enable) { - ret = clk_set_rate(clk, clk_round_rate(clk, rate)); + ret = clk_set_rate(clk, rate); if (0 == ret) ret = clk_enable(clk); } else { @@ -585,7 +585,56 @@ static int __fsi_set_rate(struct clk *clk, long rate, int enable) return ret; } -static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +static int __fsi_set_round_rate(struct clk *clk, long rate, int enable) +{ + return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable); +} + +static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable) +{ + struct clk *fsia_ick; + struct clk *fsiack; + int ret = -EIO; + + fsia_ick = clk_get(dev, "icka"); + if (IS_ERR(fsia_ick)) + return PTR_ERR(fsia_ick); + + /* + * FSIACK is connected to AK4642, + * and use external clock pin from it. + * it is parent of fsia_ick now. + */ + fsiack = clk_get_parent(fsia_ick); + if (!fsiack) + goto fsia_ick_out; + + /* + * we get 1/1 divided clock by setting same rate to fsiack and fsia_ick + * + ** FIXME ** + * Because the freq_table of external clk (fsiack) are all 0, + * the return value of clk_round_rate became 0. + * So, it use __fsi_set_rate here. + */ + ret = __fsi_set_rate(fsiack, rate, enable); + if (ret < 0) + goto fsiack_out; + + ret = __fsi_set_round_rate(fsia_ick, rate, enable); + if ((ret < 0) && enable) + __fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */ + +fsiack_out: + clk_put(fsiack); + +fsia_ick_out: + clk_put(fsia_ick); + + return 0; +} + +static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; @@ -594,10 +643,6 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) int ackmd_bpfmd; int ret; - /* set_rate is not needed if port A */ - if (is_porta) - return 0; - switch (rate) { case 44100: fsib_rate = rate * 256; @@ -618,23 +663,35 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) if (IS_ERR(fsib_clk)) return -EIO; - ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); + ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); if (ret < 0) return ret; /* FSI DIV setting */ - ret = __fsi_set_rate(fdiv_clk, fdiv_rate, enable); + ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable); if (ret < 0) { /* disable FSI B */ if (enable) - __fsi_set_rate(fsib_clk, fsib_rate, 0); + __fsi_set_round_rate(fsib_clk, fsib_rate, 0); return ret; } return ackmd_bpfmd; } +static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +{ + int ret; + + if (is_porta) + ret = fsi_ak4642_set_rate(dev, rate, enable); + else + ret = fsi_hdmi_set_rate(dev, rate, enable); + + return ret; +} + static struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | @@ -928,23 +985,11 @@ out: device_initcall(hdmi_init_pm_clock); -#define FSIACK_DUMMY_RATE 48000 static int __init fsi_init_pm_clock(void) { struct clk *fsia_ick; int ret; - /* - * FSIACK is connected to AK4642, - * and the rate is depend on playing sound rate. - * So, set dummy rate (= 48k) here - */ - ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE); - if (ret < 0) { - pr_err("Cannot set FSIACK dummy rate: %d\n", ret); - return ret; - } - fsia_ick = clk_get(&fsi_device.dev, "icka"); if (IS_ERR(fsia_ick)) { ret = PTR_ERR(fsia_ick); @@ -953,16 +998,9 @@ static int __init fsi_init_pm_clock(void) } ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); - if (ret < 0) { - pr_err("Cannot set FSI-A parent: %d\n", ret); - goto out; - } - - ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE); if (ret < 0) - pr_err("Cannot set FSI-A rate: %d\n", ret); + pr_err("Cannot set FSI-A parent: %d\n", ret); -out: clk_put(fsia_ick); return ret; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 136414f163e9..4c2404b1b862 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -902,18 +902,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, struct fsi_master *master = fsi_get_master(fsi); int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); int fsi_ver = master->core->ver; - int is_play = fsi_is_play(substream); long rate = params_rate(params); int ret; - /* if slave mode, set_rate is not needed */ - if (!fsi_is_master_mode(fsi, is_play)) - return 0; - - /* it is error if no set_rate */ set_rate = master->info->set_rate; if (!set_rate) - return -EIO; + return 0; ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); if (ret < 0) /* error */ -- cgit v1.2.3 From a57b1a9bdfb61e8d7dc7acc5e2d8bc04c549e668 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:26 +0000 Subject: ARM: mach-shmobile: clock-sh7372: modify error code Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 4191e2921127..41663e0ca104 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -454,7 +454,7 @@ static int fsidiv_enable(struct clk *clk) value = __raw_readl(clk->mapping->base) >> 16; if (value < 2) - return -ENOENT; + return -EIO; __raw_writel((value << 16) | 0x3, clk->mapping->base); @@ -468,7 +468,7 @@ static int fsidiv_set_rate(struct clk *clk, idx = (clk->parent->rate / rate) & 0xffff; if (idx < 2) - return -ENOENT; + return -EINVAL; __raw_writel(idx << 16, clk->mapping->base); return 0; -- cgit v1.2.3 From b16a2892b9852839307894cc429b7a7b145138a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:32 +0000 Subject: ARM: mach-shmobile: clock-sh7372: remove unnecessary fsi clocks Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 41663e0ca104..cbeca2849918 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -602,8 +602,6 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), - CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]), - CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]), CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), -- cgit v1.2.3 From 421b446abeec55bed1251fab80cb5c12be58b773 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:52 +0000 Subject: ARM: mach-shmobile: clock-sh7372: remove bogus pllc2 clock toggling. The PLLC2 clock was utilizing the same sort of enable/disable without regard to usecount approach that the FSIDIV clock was when being used as a PLL pass-through. This forces the enable/disable through the clock framework, which now prevents the clock from being ripped out or modified underneath users that have an existing handle on it. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 5 +++++ arch/arm/mach-shmobile/clock-sh7372.c | 12 ++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index e084b423146e..d440e5f456ad 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -969,6 +969,11 @@ static int __init hdmi_init_pm_clock(void) goto out; } + ret = clk_enable(&sh7372_pllc2_clk); + if (ret < 0) { + pr_err("Cannot enable pllc2 clock\n"); + goto out; + } pr_debug("PLLC2 set frequency %lu\n", rate); ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index cbeca2849918..e18a1241a95e 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -230,21 +230,13 @@ static int pllc2_set_rate(struct clk *clk, if (idx < 0) return idx; - if (rate == clk->parent->rate) { - pllc2_disable(clk); - return 0; - } + if (rate == clk->parent->rate) + return -EINVAL; value = __raw_readl(PLLC2CR) & ~(0x3f << 24); - if (value & 0x80000000) - pllc2_disable(clk); - __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR); - if (value & 0x80000000) - return pllc2_enable(clk); - return 0; } -- cgit v1.2.3