From 7dc341175af5e7361af81499ea192c7b274b6357 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Tue, 4 Dec 2012 15:21:52 +0100 Subject: xen-blkback: implement safe iterator for the list of persistent grants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change foreach_grant iterator to a safe version, that allows freeing the element while iterating. Also move the free code in free_persistent_gnts to prevent freeing the element before the rb_next call. Reported-by: Dan Carpenter Signed-off-by: Roger Pau Monné Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xen.org Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 74374fb762aa..5ac841ff6cc7 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -161,10 +161,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, static void make_response(struct xen_blkif *blkif, u64 id, unsigned short op, int st); -#define foreach_grant(pos, rbtree, node) \ - for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node); \ +#define foreach_grant_safe(pos, n, rbtree, node) \ + for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \ + (n) = rb_next(&(pos)->node); \ &(pos)->node != NULL; \ - (pos) = container_of(rb_next(&(pos)->node), typeof(*(pos)), node)) + (pos) = container_of(n, typeof(*(pos)), node), \ + (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL) static void add_persistent_gnt(struct rb_root *root, @@ -217,10 +219,11 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num) struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct persistent_gnt *persistent_gnt; + struct rb_node *n; int ret = 0; int segs_to_unmap = 0; - foreach_grant(persistent_gnt, root, node) { + foreach_grant_safe(persistent_gnt, n, root, node) { BUG_ON(persistent_gnt->handle == BLKBACK_INVALID_HANDLE); gnttab_set_unmap_op(&unmap[segs_to_unmap], @@ -230,9 +233,6 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num) persistent_gnt->handle); pages[segs_to_unmap] = persistent_gnt->page; - rb_erase(&persistent_gnt->node, root); - kfree(persistent_gnt); - num--; if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || !rb_next(&persistent_gnt->node)) { @@ -241,6 +241,10 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num) BUG_ON(ret); segs_to_unmap = 0; } + + rb_erase(&persistent_gnt->node, root); + kfree(persistent_gnt); + num--; } BUG_ON(num != 0); } -- cgit v1.2.3-59-g8ed1b From ebb351cf78ee6bf3262e6b4b6906f456c05e6d5e Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Tue, 4 Dec 2012 15:21:53 +0100 Subject: llist/xen-blkfront: implement safe version of llist_for_each_entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a safe version of llist_for_each_entry, and use it in blkif_free. Previously grants where freed while iterating the list, which lead to dereferences when trying to fetch the next item. Reported-by: Dan Carpenter Signed-off-by: Roger Pau Monné Acked-by: Andrew Morton [v2: Move the llist_for_each_entry_safe in llist.h] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 3 ++- include/linux/llist.h | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 96e9b00db081..cfdb033c7107 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -792,6 +792,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) { struct llist_node *all_gnts; struct grant *persistent_gnt; + struct llist_node *n; /* Prevent new requests being issued until we fix things up. */ spin_lock_irq(&info->io_lock); @@ -804,7 +805,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) /* Remove all persistent grants */ if (info->persistent_gnts_c) { all_gnts = llist_del_all(&info->persistent_gnts); - llist_for_each_entry(persistent_gnt, all_gnts, node) { + llist_for_each_entry_safe(persistent_gnt, n, all_gnts, node) { gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); __free_page(pfn_to_page(persistent_gnt->pfn)); kfree(persistent_gnt); diff --git a/include/linux/llist.h b/include/linux/llist.h index a5199f6d0e82..d0ab98f73d38 100644 --- a/include/linux/llist.h +++ b/include/linux/llist.h @@ -124,6 +124,31 @@ static inline void init_llist_head(struct llist_head *list) &(pos)->member != NULL; \ (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member)) +/** + * llist_for_each_entry_safe - iterate safely against remove over some entries + * of lock-less list of given type. + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as a temporary storage. + * @node: the fist entry of deleted list entries. + * @member: the name of the llist_node with the struct. + * + * In general, some entries of the lock-less list can be traversed + * safely only after being removed from list, so start with an entry + * instead of list head. This variant allows removal of entries + * as we iterate. + * + * If being used on entries deleted from lock-less list directly, the + * traverse order is from the newest to the oldest added entry. If + * you want to traverse from the oldest to the newest, you must + * reverse the order by yourself before traversing. + */ +#define llist_for_each_entry_safe(pos, n, node, member) \ + for ((pos) = llist_entry((node), typeof(*(pos)), member), \ + (n) = (pos)->member.next; \ + &(pos)->member != NULL; \ + (pos) = llist_entry(n, typeof(*(pos)), member), \ + (n) = (&(pos)->member != NULL) ? (pos)->member.next : NULL) + /** * llist_empty - tests whether a lock-less list is empty * @head: the list to test -- cgit v1.2.3-59-g8ed1b From d62f691858252333ff1ddb920e6774d9020734aa Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Fri, 7 Dec 2012 19:00:31 +0100 Subject: xen-blkfront: handle bvecs with partial data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently blkfront fails to handle cases in blkif_completion like the following: 1st loop in rq_for_each_segment * bv_offset: 3584 * bv_len: 512 * offset += bv_len * i: 0 2nd loop: * bv_offset: 0 * bv_len: 512 * i: 0 In the second loop i should be 1, since we assume we only wanted to read a part of the previous page. This patches fixes this cases where only a part of the shared page is read, and blkif_completion assumes that if the bv_offset of a bvec is less than the previous bv_offset plus the bv_size we have to switch to the next shared page. Reported-by: Konrad Rzeszutek Wilk Signed-off-by: Roger Pau Monné Cc: linux-kernel@vger.kernel.org Cc: Konrad Rzeszutek Wilk Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index cfdb033c7107..11043c18ac5a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -836,7 +836,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, struct blkif_response *bret) { - int i; + int i = 0; struct bio_vec *bvec; struct req_iterator iter; unsigned long flags; @@ -853,7 +853,8 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, */ rq_for_each_segment(bvec, s->request, iter) { BUG_ON((bvec->bv_offset + bvec->bv_len) > PAGE_SIZE); - i = offset >> PAGE_SHIFT; + if (bvec->bv_offset < offset) + i++; BUG_ON(i >= s->req.u.rw.nr_segments); shared_data = kmap_atomic( pfn_to_page(s->grants_used[i]->pfn)); @@ -862,7 +863,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, bvec->bv_len); bvec_kunmap_irq(bvec_data, &flags); kunmap_atomic(shared_data); - offset += bvec->bv_len; + offset = bvec->bv_offset + bvec->bv_len; } } /* Add the persistent grant into the list of free grants */ -- cgit v1.2.3-59-g8ed1b From aea24a8bbc81c8b404e4e293fb37aefaf388d35d Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Tue, 18 Dec 2012 12:27:18 -0800 Subject: block: remove deadlock in disk_clear_events In disk_clear_events, do not put work on system_nrt_freezable_wq. Instead, put it on system_nrt_wq. There is a race between probing a usb and suspending the device. Since probing a usb calls disk_clear_events, which puts work on a frozen workqueue, probing cannot finish after the workqueue is frozen. However, suspending cannot finish until the usb probe is finished, so we get a deadlock, causing the system to reboot. The way to reproduce this bug is to wake up from suspend with a usb storage device plugged in, or plugging in a usb storage device right before suspend. The window of time is on the order of time it takes to probe the usb device. As long as the workqueues are frozen before the call to add_disk within sd_probe_async finishes, there will be a deadlock (which calls blkdev_get, sd_open, check_disk_change, then disk_clear_events). This is not difficult to reproduce after figuring out the timings. [akpm@linux-foundation.org: fix up comment] Signed-off-by: Derek Basehore Reviewed-by: Mandeep Singh Baines Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/genhd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/block/genhd.c b/block/genhd.c index 9a289d7c84bb..33a3b38aa4b2 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1565,7 +1565,14 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) /* uncondtionally schedule event check and wait for it to finish */ disk_block_events(disk); - queue_delayed_work(system_freezable_wq, &ev->dwork, 0); + /* + * We need to put the work on system_nrt_wq here since there is a + * deadlock that happens while probing a usb device while suspending. If + * we put work on a freezable workqueue here, a usb probe will wait here + * until the workqueue is unfrozen during suspend. Since suspend waits + * on all probes to complete, we have a deadlock + */ + queue_delayed_work(system_nrt_wq, &ev->dwork, 0); flush_delayed_work(&ev->dwork); __disk_unblock_events(disk, false); -- cgit v1.2.3-59-g8ed1b From 12c2bdb232168511c8dd54d6626549391a228918 Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Tue, 18 Dec 2012 12:27:20 -0800 Subject: block: prevent race/cleanup Remove a race condition which causes a warning in disk_clear_events. This is a race between disk_clear_events() and disk_flush_events(). ev->clearing will be altered by disk_flush_events() even though we are blocking event checking through disk_flush_events(). If this happens after ev->clearing was cleared for disk_clear_events(), this can cause the WARN_ON_ONCE() in that function to be triggered. This change also has disk_clear_events() not go through a workqueue. Since we have to wait for the work to complete, we should just call the function directly. Also, since this work cannot be put on a freezable workqueue, it will have to contend with increased demand, so calling the function directly avoids this. [akpm@linux-foundation.org: fix spello in comment] Signed-off-by: Derek Basehore Cc: Mandeep Singh Baines Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/genhd.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 33a3b38aa4b2..3993ebf4135f 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -35,6 +35,8 @@ static DEFINE_IDR(ext_devt_idr); static struct device_type disk_type; +static void disk_check_events(struct disk_events *ev, + unsigned int *clearing_ptr); static void disk_alloc_events(struct gendisk *disk); static void disk_add_events(struct gendisk *disk); static void disk_del_events(struct gendisk *disk); @@ -1549,6 +1551,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) const struct block_device_operations *bdops = disk->fops; struct disk_events *ev = disk->ev; unsigned int pending; + unsigned int clearing = mask; if (!ev) { /* for drivers still using the old ->media_changed method */ @@ -1558,41 +1561,53 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) return 0; } - /* tell the workfn about the events being cleared */ + disk_block_events(disk); + + /* + * store the union of mask and ev->clearing on the stack so that the + * race with disk_flush_events does not cause ambiguity (ev->clearing + * can still be modified even if events are blocked). + */ spin_lock_irq(&ev->lock); - ev->clearing |= mask; + clearing |= ev->clearing; + ev->clearing = 0; spin_unlock_irq(&ev->lock); - /* uncondtionally schedule event check and wait for it to finish */ - disk_block_events(disk); + disk_check_events(ev, &clearing); /* - * We need to put the work on system_nrt_wq here since there is a - * deadlock that happens while probing a usb device while suspending. If - * we put work on a freezable workqueue here, a usb probe will wait here - * until the workqueue is unfrozen during suspend. Since suspend waits - * on all probes to complete, we have a deadlock + * if ev->clearing is not 0, the disk_flush_events got called in the + * middle of this function, so we want to run the workfn without delay. */ - queue_delayed_work(system_nrt_wq, &ev->dwork, 0); - flush_delayed_work(&ev->dwork); - __disk_unblock_events(disk, false); + __disk_unblock_events(disk, ev->clearing ? true : false); /* then, fetch and clear pending events */ spin_lock_irq(&ev->lock); - WARN_ON_ONCE(ev->clearing & mask); /* cleared by workfn */ pending = ev->pending & mask; ev->pending &= ~mask; spin_unlock_irq(&ev->lock); + WARN_ON_ONCE(clearing & mask); return pending; } +/* + * Separate this part out so that a different pointer for clearing_ptr can be + * passed in for disk_clear_events. + */ static void disk_events_workfn(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct disk_events *ev = container_of(dwork, struct disk_events, dwork); + + disk_check_events(ev, &ev->clearing); +} + +static void disk_check_events(struct disk_events *ev, + unsigned int *clearing_ptr) +{ struct gendisk *disk = ev->disk; char *envp[ARRAY_SIZE(disk_uevents) + 1] = { }; - unsigned int clearing = ev->clearing; + unsigned int clearing = *clearing_ptr; unsigned int events; unsigned long intv; int nr_events = 0, i; @@ -1605,7 +1620,7 @@ static void disk_events_workfn(struct work_struct *work) events &= ~ev->pending; ev->pending |= events; - ev->clearing &= ~clearing; + *clearing_ptr &= ~clearing; intv = disk_events_poll_jiffies(disk); if (!ev->block && intv) -- cgit v1.2.3-59-g8ed1b From 5a40b5fb2bb3a4d1c20149fe47ab25409026ee2e Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 24 Dec 2012 17:34:29 +0100 Subject: mtd: bcm47xxnflash: increase NFLASH_READY_RETRIES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recently imlemented writing support has shown that current num of retries is too low. Writing requires longer waiting than simple reading. Signed-off-by: Rafał Miłecki Signed-off-by: David Woodhouse --- drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 86c9a79b89b3..595de4012e71 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -17,8 +17,8 @@ #include "bcm47xxnflash.h" /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has - * shown 164 retries as maxiumum. */ -#define NFLASH_READY_RETRIES 1000 + * shown ~1000 retries as maxiumum. */ +#define NFLASH_READY_RETRIES 10000 #define NFLASH_SECTOR_SIZE 512 -- cgit v1.2.3-59-g8ed1b From 353af9c9a866b07492b15a4efd18ec93123d3a1d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 20 Dec 2012 09:35:02 -0800 Subject: rcu: Prevent soft-lockup complaints about no-CBs CPUs The wait_event() at the head of the rcu_nocb_kthread() can result in soft-lockup complaints if the CPU in question does not register RCU callbacks for an extended period. This commit therefore changes the wait_event() to a wait_event_interruptible(). Reported-by: Frederic Weisbecker Signed-off-by: Paul Gortmaker Signed-off-by: Paul E. McKenney --- kernel/rcutree_plugin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index f6e5ec2932b4..43dba2d798ac 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -2366,10 +2366,11 @@ static int rcu_nocb_kthread(void *arg) for (;;) { /* If not polling, wait for next batch of callbacks. */ if (!rcu_nocb_poll) - wait_event(rdp->nocb_wq, rdp->nocb_head); + wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); list = ACCESS_ONCE(rdp->nocb_head); if (!list) { schedule_timeout_interruptible(1); + flush_signals(current); continue; } -- cgit v1.2.3-59-g8ed1b From 1b0048a44c502c5ab850203e6e0a6498d7d8676d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 20 Dec 2012 13:19:22 -0800 Subject: rcu: Make rcu_nocb_poll an early_param instead of module_param The as-documented rcu_nocb_poll will fail to enable this feature for two reasons. (1) there is an extra "s" in the documented name which is not in the code, and (2) since it uses module_param, it really is expecting a prefix, akin to "rcutree.fanout_leaf" and the prefix isn't documented. However, there are several reasons why we might not want to simply fix the typo and add the prefix: 1) we'd end up with rcutree.rcu_nocb_poll, and rather probably make a change to rcutree.nocb_poll 2) if we did #1, then the prefix wouldn't be consistent with the rcu_nocbs= parameter (i.e. one with, one without prefix) 3) the use of module_param in a header file is less than desired, since it isn't immediately obvious that it will get processed via rcutree.c and get the prefix from that (although use of module_param_named() could clarify that.) 4) the implied export of /sys/module/rcutree/parameters/rcu_nocb_poll data to userspace via module_param() doesn't really buy us anything, as it is read-only and we can tell if it is enabled already without it, since there is a printk at early boot telling us so. In light of all that, just change it from a module_param() to an early_setup() call, and worry about adding it to /sys later on if we decide to allow a dynamic setting of it. Also change the variable to be tagged as read_mostly, since it will only ever be fiddled with at most, once at boot. Signed-off-by: Paul Gortmaker Signed-off-by: Paul E. McKenney --- Documentation/kernel-parameters.txt | 2 +- kernel/rcutree_plugin.h | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 363e348bff9b..6c723811c0a0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2438,7 +2438,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. real-time workloads. It can also improve energy efficiency for asymmetric multiprocessors. - rcu_nocbs_poll [KNL,BOOT] + rcu_nocb_poll [KNL,BOOT] Rather than requiring that offloaded CPUs (specified by rcu_nocbs= above) explicitly awaken the corresponding "rcuoN" kthreads, diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 43dba2d798ac..c1cc7e17ff9d 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -40,8 +40,7 @@ #ifdef CONFIG_RCU_NOCB_CPU static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */ static bool have_rcu_nocb_mask; /* Was rcu_nocb_mask allocated? */ -static bool rcu_nocb_poll; /* Offload kthread are to poll. */ -module_param(rcu_nocb_poll, bool, 0444); +static bool __read_mostly rcu_nocb_poll; /* Offload kthread are to poll. */ static char __initdata nocb_buf[NR_CPUS * 5]; #endif /* #ifdef CONFIG_RCU_NOCB_CPU */ @@ -2159,6 +2158,13 @@ static int __init rcu_nocb_setup(char *str) } __setup("rcu_nocbs=", rcu_nocb_setup); +static int __init parse_rcu_nocb_poll(char *arg) +{ + rcu_nocb_poll = 1; + return 0; +} +early_param("rcu_nocb_poll", parse_rcu_nocb_poll); + /* Is the specified CPU a no-CPUs CPU? */ static bool is_nocb_cpu(int cpu) { -- cgit v1.2.3-59-g8ed1b From 47cd4b3c7e80cc8d5ac82930c5af835870b5aba1 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Fri, 11 Jan 2013 18:46:04 +0530 Subject: mtip32xx: fix for driver hang after a command timeout If an I/O command times out when a PIO command is active, MTIP_PF_EH_ACTIVE_BIT is not cleared. This results in I/O hang in the driver. Fix is to clear this bit. Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 9694dd99bbbc..b93282019632 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -626,12 +626,13 @@ static void mtip_timeout_function(unsigned long int data) } } - if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { + if (cmdto_cnt) { print_tags(port->dd, "timed out", tagaccum, cmdto_cnt); - - mtip_restart_port(port); + if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { + mtip_restart_port(port); + wake_up_interruptible(&port->svc_wait); + } clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); - wake_up_interruptible(&port->svc_wait); } if (port->ic_pause_timer) { -- cgit v1.2.3-59-g8ed1b From 58c49df378cde4ff64172483d593a1a5689c13a8 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Fri, 11 Jan 2013 18:47:12 +0530 Subject: mtip32xx: fix for crash when the device surprise removed during rebuild When rebuild is in progress, disk->queue is yet to be created. Surprise removing the device will call remove()-> del_gendisk(). del_gendisk() expect disk->queue be not NULL. Fix is to call put_disk() when disk_queue is NULL. Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index b93282019632..3fd100990453 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3888,7 +3888,12 @@ static int mtip_block_remove(struct driver_data *dd) * Delete our gendisk structure. This also removes the device * from /dev */ - del_gendisk(dd->disk); + if (dd->disk) { + if (dd->disk->queue) + del_gendisk(dd->disk); + else + put_disk(dd->disk); + } spin_lock(&rssd_index_lock); ida_remove(&rssd_index_ida, dd->index); @@ -3922,7 +3927,13 @@ static int mtip_block_shutdown(struct driver_data *dd) "Shutting down %s ...\n", dd->disk->disk_name); /* Delete our gendisk structure, and cleanup the blk queue. */ - del_gendisk(dd->disk); + if (dd->disk) { + if (dd->disk->queue) + del_gendisk(dd->disk); + else + put_disk(dd->disk); + } + spin_lock(&rssd_index_lock); ida_remove(&rssd_index_ida, dd->index); -- cgit v1.2.3-59-g8ed1b From 7a9c83888761a9a26049b439dc0b09e7ea8a854b Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 3 Jan 2013 21:27:34 +0300 Subject: mtd: davinci_nand: fix modular build with CONFIG_OF=y Commit cdeadd712f52b16a9285386d61ee26fd14eb4085 (mtd: nand: davinci: add OF support for davinci nand controller) has never been really build tested with the driver as a module. When the driver is built-in, the missing semicolon after structure initializer is "compensated" by MODULE_DEVICE_TABLE() macro being empty and so the initializer using the trailing semicolon on the next line; when the driver is built as a module, compilation error ensues, and as the 'davinci_all_defconfig' has the NAND driver modular, this error prevents DaVinci family kernel from building... Signed-off-by: Sergei Shtylyov Signed-off-by: David Woodhouse Cc: stable@vger.kernel.org # 3.7 --- drivers/mtd/nand/davinci_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 3502606f6480..feae55c7b880 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -523,7 +523,7 @@ static struct nand_ecclayout hwecc4_2048 __initconst = { static const struct of_device_id davinci_nand_of_match[] = { {.compatible = "ti,davinci-nand", }, {}, -} +}; MODULE_DEVICE_TABLE(of, davinci_nand_of_match); static struct davinci_nand_pdata -- cgit v1.2.3-59-g8ed1b From bf65aaa637cabae0386fe46b1ad5cd16997474f5 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 14 Jan 2013 20:01:37 +0100 Subject: mtd: docg3 fix missing bitreverse lib Fix missing dependency which can cause a build error such as: ERROR: "byte_rev_table" [drivers/mtd/devices/docg3.ko] undefined! Reported-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Robert Jarzmik Signed-off-by: David Woodhouse --- drivers/mtd/devices/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 27f80cd8aef3..46dcb54c32ec 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -272,6 +272,7 @@ config MTD_DOCG3 tristate "M-Systems Disk-On-Chip G3" select BCH select BCH_CONST_PARAMS + select BITREVERSE ---help--- This provides an MTD device driver for the M-Systems DiskOnChip G3 devices. -- cgit v1.2.3-59-g8ed1b From 7dfe4be351e81656ca1068e5d4ead235c7ba94b1 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 23 Dec 2012 13:10:50 +0200 Subject: mtd: physmap_of: fix cmdline partition method w/o linux, mtd-name Commit d68cbdd4fb (mtd: physmap_of: allow to specify the mtd name for retro compatiblity) broke cmdline partitioning using dev_name() in the kernel command line. of_property_read_string() does not touch mtd_name when linux,mtd-name is not present in the device tree, which causes map.name to be set to a random value. Fix this by initializing mtd_name to NULL. Cc: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Baruch Siach Signed-off-by: David Woodhouse --- drivers/mtd/maps/physmap_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 37cdc201652f..6fb2bd83d7de 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -170,7 +170,7 @@ static int of_flash_probe(struct platform_device *dev) resource_size_t res_size; struct mtd_part_parser_data ppdata; bool map_indirect; - const char *mtd_name; + const char *mtd_name = NULL; match = of_match_device(of_flash_match, &dev->dev); if (!match) -- cgit v1.2.3-59-g8ed1b From 0ce82b7f7b7373b16ecf7b5725e21e2975204500 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Wed, 16 Jan 2013 15:25:45 +0100 Subject: mtd: nand: onfi don't WARN if we are in 16 bits mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ff3206b2450499203532af2505a7f6f8413e92c0 ('mtd: nand: onfi need to be probed in 8 bits mode') adds a WARN if the onfi probe is in 16 bits mode. This allows to detect driver that need to be fixed, but this is a bit noisy¹. Transform the WARN in a pr_err. ¹ http://article.gmane.org/gmane.linux.ports.arm.omap/91317 Signed-off-by: Matthieu CASTET Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8323ac991ad1..3766682a0289 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2857,8 +2857,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; - /* ONFI need to be probed in 8 bits mode */ - WARN_ON(chip->options & NAND_BUSWIDTH_16); + /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */ + if (chip->options & NAND_BUSWIDTH_16) { + pr_err("Trying ONFI probe in 16 bits mode, aborting !\n"); + return 0; + } /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || -- cgit v1.2.3-59-g8ed1b From 2681f7f6ce6c7416eb619d0fb19422bcc68bd9e1 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 21 Jan 2013 15:43:41 +0100 Subject: drbd: fix potential protocol error and resulting disconnect/reconnect When we notice a disk failure on the receiving side, we stop sending it new incoming writes. Depending on exact timing of various events, the same transfer log epoch could end up containing both replicated (before we noticed the failure) and local-only requests (after we noticed the failure). The sanity checks in tl_release(), called when receiving a P_BARRIER_ACK, check that the ack'ed transfer log epoch matches the expected epoch, and the number of contained writes matches the number of ack'ed writes. In this case, they counted both replicated and local-only writes, but the peer only acknowledges those it has seen. We get a mismatch, resulting in a protocol error and disconnect/reconnect cycle. Messages logged are "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n" A similar issue can also be triggered when starting a resync while having a healthy replication link, by invalidating one side, forcing a full sync, or attaching to a diskless node. Fix this by closing the current epoch if the state changes in a way that would cause the replication intent of the next write. Epochs now contain either only non-replicated, or only replicated writes. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 2 +- drivers/block/drbd/drbd_req.h | 1 + drivers/block/drbd/drbd_state.c | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index f58a4a4b4dfb..2b8303ad63c9 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -168,7 +168,7 @@ static void wake_all_senders(struct drbd_tconn *tconn) { } /* must hold resource->req_lock */ -static void start_new_tl_epoch(struct drbd_tconn *tconn) +void start_new_tl_epoch(struct drbd_tconn *tconn) { /* no point closing an epoch, if it is empty, anyways. */ if (tconn->current_tle_writes == 0) diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 016de6b8bb57..c08d22964d06 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -267,6 +267,7 @@ struct bio_and_error { int error; }; +extern void start_new_tl_epoch(struct drbd_tconn *tconn); extern void drbd_req_destroy(struct kref *kref); extern void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m); diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 53bf6182bac4..0fe220cfb9e9 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -931,6 +931,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, enum drbd_state_rv rv = SS_SUCCESS; enum sanitize_state_warnings ssw; struct after_state_chg_work *ascw; + bool did_remote, should_do_remote; os = drbd_read_state(mdev); @@ -981,11 +982,17 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) atomic_inc(&mdev->local_cnt); + did_remote = drbd_should_do_remote(mdev->state); mdev->state.i = ns.i; + should_do_remote = drbd_should_do_remote(mdev->state); mdev->tconn->susp = ns.susp; mdev->tconn->susp_nod = ns.susp_nod; mdev->tconn->susp_fen = ns.susp_fen; + /* put replicated vs not-replicated requests in seperate epochs */ + if (did_remote != should_do_remote) + start_new_tl_epoch(mdev->tconn); + if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) drbd_print_uuids(mdev, "attached to UUIDs"); -- cgit v1.2.3-59-g8ed1b From d9d59089c43fc33eb403cbb928e56c131f191dd5 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Mon, 21 Jan 2013 23:57:26 -0800 Subject: openvswitch: Move LRO check from transmit to receive. The check for LRO packets was incorrectly put in the transmit path instead of on receive. Since this check is supposed to protect OVS (and other parts of the system) from packets that it cannot handle it is obviously not useful on egress. Therefore, this commit moves it back to the receive side. The primary problem that this caused is upcalls to userspace tried to segment the packet even though no segmentation information is available. This would later cause NULL pointer dereferences when skb_gso_segment() did nothing. Signed-off-by: Jesse Gross --- net/openvswitch/vport-netdev.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index a9327e2e48ce..670cbc3518de 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -35,10 +35,11 @@ /* Must be called with rcu_read_lock. */ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) { - if (unlikely(!vport)) { - kfree_skb(skb); - return; - } + if (unlikely(!vport)) + goto error; + + if (unlikely(skb_warn_if_lro(skb))) + goto error; /* Make our own copy of the packet. Otherwise we will mangle the * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). @@ -50,6 +51,10 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) skb_push(skb, ETH_HLEN); ovs_vport_receive(vport, skb); + return; + +error: + kfree_skb(skb); } /* Called with rcu_read_lock and bottom-halves disabled. */ @@ -169,9 +174,6 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) goto error; } - if (unlikely(skb_warn_if_lro(skb))) - goto error; - skb->dev = netdev_vport->dev; len = skb->len; dev_queue_xmit(skb); -- cgit v1.2.3-59-g8ed1b From 5bce833c44d53ef5a31b844cf7678ddaeb406624 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 24 Jan 2013 10:27:30 +0800 Subject: regulator: tps65217: Fix using wrong dev argument for calling of_regulator_match The dev parameter is the device requestiong the data. In this case it should be &pdev->dev rather than pdev->dev.parent. The dev parameter is used to call devm_kzalloc in of_get_regulator_init_data(), which means this fixes a memory leak because the memory is allocated every time probe() is called, thus it should be freed when this driver is unloaded. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/tps65217-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 73dce7664126..df395187c063 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -305,8 +305,8 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) if (!regs) return NULL; - count = of_regulator_match(pdev->dev.parent, regs, - reg_matches, TPS65217_NUM_REGULATOR); + count = of_regulator_match(&pdev->dev, regs, reg_matches, + TPS65217_NUM_REGULATOR); of_node_put(regs); if ((count < 0) || (count > TPS65217_NUM_REGULATOR)) return NULL; -- cgit v1.2.3-59-g8ed1b From 08337fdac215d8583770c34e7449c88947aceda8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 24 Jan 2013 10:31:45 +0800 Subject: regulator: tps65910: Fix using wrong dev argument for calling of_regulator_match The dev parameter is the device requesting the data. In this case it should be &pdev->dev rather than pdev->dev.parent. The dev parameter is used to call devm_kzalloc in of_get_regulator_init_data(), which means this fixes a memory leak because the memory is allocated every time probe() is called, thus it should be freed when this driver is unloaded. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/tps65910-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 59c3770fa77d..b0e4c0bc85c3 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -998,7 +998,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( return NULL; } - ret = of_regulator_match(pdev->dev.parent, regulators, matches, count); + ret = of_regulator_match(&pdev->dev, regulators, matches, count); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); -- cgit v1.2.3-59-g8ed1b From ae023b2795d36f0f077e157428eb7eafa29ee412 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jan 2013 13:12:57 +0200 Subject: Revert "iwlwifi: fix the reclaimed packet tracking upon flush queue" This reverts commit f590dcec944552f9a4a61155810f3abd17d6465d which has been reported to cause issues. See https://lkml.org/lkml/2013/1/20/4 for further details. Cc: stable@vger.kernel.org [3.7] Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/tx.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 31534f7c0548..279796419ea0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1153,6 +1153,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, next_reclaimed = ssn; } + if (tid != IWL_TID_NON_QOS) { + priv->tid_data[sta_id][tid].next_reclaimed = + next_reclaimed; + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", + next_reclaimed); + } + iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); iwlagn_check_ratid_empty(priv, sta_id, tid); @@ -1203,28 +1210,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!is_agg) iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); - /* - * W/A for FW bug - the seq_ctl isn't updated when the - * queues are flushed. Fetch it from the packet itself - */ - if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { - next_reclaimed = le16_to_cpu(hdr->seq_ctrl); - next_reclaimed = - SEQ_TO_SN(next_reclaimed + 0x10); - } - is_offchannel_skb = (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); freed++; } - if (tid != IWL_TID_NON_QOS) { - priv->tid_data[sta_id][tid].next_reclaimed = - next_reclaimed; - IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", - next_reclaimed); - } - WARN_ON(!is_agg && freed != 1); /* -- cgit v1.2.3-59-g8ed1b From 0927b482ae69acb7605f6be1ad3860b657512fbd Mon Sep 17 00:00:00 2001 From: ShuoX Liu Date: Sat, 29 Dec 2012 00:48:44 +0800 Subject: perf/x86: Enable Intel Lincroft/Penwell/Cloverview Atom support These three chip are based on Atom and have different model id. So add such three id for perf HW event support. Signed-off-by: ShuoX Liu Cc: yanmin_zhang@intel.linux.com Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1356713324-12442-1-git-send-email-shuox.liu@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 93b9e1181f83..cb313a56c21b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2019,7 +2019,10 @@ __init int intel_pmu_init(void) break; case 28: /* Atom */ - case 54: /* Cedariew */ + case 38: /* Lincroft */ + case 39: /* Penwell */ + case 53: /* Cloverview */ + case 54: /* Cedarview */ memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, sizeof(hw_cache_event_ids)); -- cgit v1.2.3-59-g8ed1b From c49dc9008b1c641a86837297df7c90cef070571b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Jan 2013 09:40:00 +0300 Subject: cfg80211: off by one in ieee80211_bss() We do a: sprintf(buf, " Last beacon: %ums ago", elapsed_jiffies_msecs(bss->ts)); elapsed_jiffies_msecs() can return a 10 digit number so "buf" needs to be 31 characters long. Signed-off-by: Dan Carpenter Signed-off-by: Johannes Berg --- net/wireless/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 01592d7d4789..45f1618c8e23 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1358,7 +1358,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, &iwe, IW_EV_UINT_LEN); } - buf = kmalloc(30, GFP_ATOMIC); + buf = kmalloc(31, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; -- cgit v1.2.3-59-g8ed1b From 55a6e622e66a27ab106fae00cac15ba630e7fbd4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 18 Dec 2012 12:22:12 -0800 Subject: arch/x86/tools/insn_sanity.c: Identify source of messages The kernel build prints: Building modules, stage 2. TEST posttest MODPOST 3821 modules TEST posttest Success: decoded and checked 1000000 random instructions with 0 errors (seed:0xaac4bc47) CC arch/x86/boot/a20.o CC arch/x86/boot/cmdline.o AS arch/x86/boot/copy.o HOSTCC arch/x86/boot/mkcpustr CC arch/x86/boot/cpucheck.o CC arch/x86/boot/early_serial_console.o which is irritating because you don't know what program is proudly pronouncing its success. So, as described in "console mode programming user interface guidelines version 101" which doesn't exist, change this program to identify the source of its messages. Signed-off-by: Andrew Morton Cc: "H. Peter Anvin" Cc: Masami Hiramatsu Signed-off-by: Ingo Molnar --- arch/x86/tools/insn_sanity.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86/tools/insn_sanity.c b/arch/x86/tools/insn_sanity.c index cc2f8c131286..872eb60e7806 100644 --- a/arch/x86/tools/insn_sanity.c +++ b/arch/x86/tools/insn_sanity.c @@ -55,7 +55,7 @@ static FILE *input_file; /* Input file name */ static void usage(const char *err) { if (err) - fprintf(stderr, "Error: %s\n\n", err); + fprintf(stderr, "%s: Error: %s\n\n", prog, err); fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog); fprintf(stderr, "\t-y 64bit mode\n"); fprintf(stderr, "\t-n 32bit mode\n"); @@ -269,7 +269,13 @@ int main(int argc, char **argv) insns++; } - fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed); + fprintf(stdout, "%s: %s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", + prog, + (errors) ? "Failure" : "Success", + insns, + (input_file) ? "given" : "random", + errors, + seed); return errors ? 1 : 0; } -- cgit v1.2.3-59-g8ed1b From 9faec5be3a27f95ee359b42c6c81b3173eb13958 Mon Sep 17 00:00:00 2001 From: yangyongqiang Date: Tue, 18 Dec 2012 12:22:25 -0800 Subject: perf/x86: Fix P6 driver section warning Fix a compile warning - 'a section type conflict' by removing __initconst. Signed-off-by: yangyongqiang Cc: Cyrill Gorcunov Cc: Vince Weaver Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_p6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c index f2af39f5dc3d..4820c232a0b9 100644 --- a/arch/x86/kernel/cpu/perf_event_p6.c +++ b/arch/x86/kernel/cpu/perf_event_p6.c @@ -19,7 +19,7 @@ static const u64 p6_perfmon_event_map[] = }; -static __initconst u64 p6_hw_cache_event_ids +static u64 p6_hw_cache_event_ids [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] [PERF_COUNT_HW_CACHE_RESULT_MAX] = -- cgit v1.2.3-59-g8ed1b From 923d8697e24847000490c187de1aeaca622611a3 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Tue, 18 Dec 2012 12:20:23 -0500 Subject: x86/perf: Add IvyBridge EP support Running the perf utility on a Ivybridge EP server we encounter "not supported" events: L1-dcache-loads L1-dcache-load-misses L1-dcache-stores L1-dcache-store-misses L1-dcache-prefetches L1-dcache-prefetch-misses This patch adds support for this processor. Signed-off-by: Youquan Song Cc: Andi Kleen Cc: Youquan Song Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1355851223-27705-1-git-send-email-youquan.song@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index cb313a56c21b..4914e94ad6e8 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2087,6 +2087,7 @@ __init int intel_pmu_init(void) pr_cont("SandyBridge events, "); break; case 58: /* IvyBridge */ + case 62: /* IvyBridge EP */ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, -- cgit v1.2.3-59-g8ed1b From 760973d2a74b93eb1697981f7448f0e62767cfc4 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 11 Jan 2013 11:19:07 -0800 Subject: xhci: Fix isoc TD encoding. An isochronous TD is comprised of one isochronous TRB chained to zero or more normal TRBs. Only the isoc TRB has the TBC and TLBPC fields. The normal TRBs must set those fields to zeroes. The code was setting the TBC and TLBPC fields for both isoc and normal TRBs. Fix this. This should be backported to stable kernels as old as 3.0, that contain the commit b61d378f2da41c748aba6ca19d77e1e1c02bcea5 " xhci 1.0: Set transfer burst last packet count field." Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-ring.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 59fb5c677dbe..d1ff13370d33 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3664,9 +3664,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td = urb_priv->td[i]; for (j = 0; j < trbs_per_td; j++) { u32 remainder = 0; - field = TRB_TBC(burst_count) | TRB_TLBPC(residue); + field = 0; if (first_trb) { + field = TRB_TBC(burst_count) | + TRB_TLBPC(residue); /* Queue the isoc TRB */ field |= TRB_TYPE(TRB_ISOC); /* Assume URB_ISO_ASAP is set */ -- cgit v1.2.3-59-g8ed1b From f18f8ed2a9adc41c2d9294b85b6af115829d2af1 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 11 Jan 2013 13:36:35 -0800 Subject: xhci: Fix TD size for isochronous URBs. To calculate the TD size for a particular TRB in an isoc TD, we need know the endpoint's max packet size. Isochronous endpoints also encode the number of additional service opportunities in their wMaxPacketSize field. The TD size calculation did not mask off those bits before using the field. This resulted in incorrect TD size information for isochronous TRBs when an URB frame buffer crossed a 64KB boundary. For example: - an isoc endpoint has 2 additional service opportunites and a max packet size of 1020 bytes - a frame transfer buffer contains 3060 bytes - one frame buffer crosses a 64KB boundary, and must be split into one 1276 byte TRB, and one 1784 byte TRB. The TD size is is the number of packets that remain to be transferred for a TD after processing all the max packet sized packets in the current TRB and all previous TRBs. For this TD, the number of packets to be transferred is (3060 / 1020), or 3. The first TRB contains 1276 bytes, which means it contains one full packet, and a 256 byte remainder. After processing all the max packet-sized packets in the first TRB, the host will have 2 packets left to transfer. The old code would calculate the TD size for the first TRB as: total packet count = DIV_ROUND_UP (TD length / endpoint wMaxPacketSize) total packet count - (first TRB length / endpoint wMaxPacketSize) The math should have been: total packet count = DIV_ROUND_UP (3060 / 1020) = 3 3 - (1276 / 1020) = 2 Since the old code didn't mask off the additional service interval bits from the wMaxPacketSize field, the math ended up as total packet count = DIV_ROUND_UP (3060 / 5116) = 1 1 - (1276 / 5116) = 1 Fix this by masking off the number of additional service opportunities in the wMaxPacketSize field. This patch should be backported to stable kernels as old as 3.0, that contain the commit 4da6e6f247a2601ab9f1e63424e4d944ed4124f3 "xhci 1.0: Update TD size field format." It may not apply well to kernels older than 3.2 because of commit 29cc88979a8818cd8c5019426e945aed118b400e "USB: use usb_endpoint_maxp() instead of le16_to_cpu()". Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-ring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d1ff13370d33..80ef717ec5b8 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3108,7 +3108,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, * running_total. */ packets_transferred = (running_total + trb_buff_len) / - usb_endpoint_maxp(&urb->ep->desc); + GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc)); if ((total_packet_count - packets_transferred) > 31) return 31 << 17; @@ -3642,7 +3642,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td_len = urb->iso_frame_desc[i].length; td_remain_len = td_len; total_packet_count = DIV_ROUND_UP(td_len, - usb_endpoint_maxp(&urb->ep->desc)); + GET_MAX_PACKET( + usb_endpoint_maxp(&urb->ep->desc))); /* A zero-length transfer still involves at least one packet. */ if (total_packet_count == 0) total_packet_count++; -- cgit v1.2.3-59-g8ed1b From ba7b5c22d33136a5612ca5ef8d31564dcc501126 Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Mon, 7 Jan 2013 22:39:31 -0500 Subject: drivers: xhci: fix incorrect bit test Fix incorrect bit test that originally showed up in 4ee823b83bc9851743fab756c76b27d6a1e2472b "USB/xHCI: Support device-initiated USB 3.0 resume." Use '&' instead of '&&'. This should be backported to kernels as old as 3.4. Signed-off-by: Nickolai Zeldovich Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 80ef717ec5b8..151204642a6e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1698,7 +1698,7 @@ static void handle_port_status(struct xhci_hcd *xhci, faked_port_index + 1); if (slot_id && xhci->devs[slot_id]) xhci_ring_device(xhci, slot_id); - if (bus_state->port_remote_wakeup && (1 << faked_port_index)) { + if (bus_state->port_remote_wakeup & (1 << faked_port_index)) { bus_state->port_remote_wakeup &= ~(1 << faked_port_index); xhci_test_and_clear_bit(xhci, port_array, -- cgit v1.2.3-59-g8ed1b From 48c3375c5f69b1c2ef3d1051a0009cb9bce0ce24 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jan 2013 10:32:16 -0500 Subject: USB: XHCI: fix memory leak of URB-private data This patch (as1640) fixes a memory leak in xhci-hcd. The urb_priv data structure isn't always deallocated in the handle_tx_event() routine for non-control transfers. The patch adds a kfree() call so that all paths end up freeing the memory properly. This patch should be backported to kernels as old as 2.6.36, that contain the commit 8e51adccd4c4b9ffcd509d7f2afce0a906139f75 "USB: xHCI: Introduce urb_priv structure" Signed-off-by: Alan Stern Signed-off-by: Sarah Sharp Reported-and-tested-by: Martin Mokrejs CC: --- drivers/usb/host/xhci-ring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 151204642a6e..7f76a49e90d3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2589,6 +2589,8 @@ cleanup: (trb_comp_code != COMP_STALL && trb_comp_code != COMP_BABBLE)) xhci_urb_free_priv(xhci, urb_priv); + else + kfree(urb_priv); usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); if ((urb->actual_length != urb->transfer_buffer_length && -- cgit v1.2.3-59-g8ed1b From 58b2939b4d5a030eaec469d29812ab8477ee7e76 Mon Sep 17 00:00:00 2001 From: David Moore Date: Wed, 23 Jan 2013 22:19:49 -0800 Subject: usb: Prevent dead ports when xhci is not enabled When the xHCI driver is not available, actively switch the ports to EHCI mode since some BIOSes leave them in xHCI mode where they would otherwise appear dead. This was discovered on a Dell Optiplex 7010, but it's possible other systems could be affected. This should be backported to kernels as old as 3.0, that contain the commit 69e848c2090aebba5698a1620604c7dccb448684 "Intel xhci: Support EHCI/xHCI port switching." Signed-off-by: David Moore Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/pci-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index a3b6d7104ae2..4c338ec03a07 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -780,6 +780,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) "defaulting to EHCI.\n"); dev_warn(&xhci_pdev->dev, "USB 3.0 devices will work at USB 2.0 speeds.\n"); + usb_disable_xhci_ports(xhci_pdev); return; } -- cgit v1.2.3-59-g8ed1b From 54a3ac0c9e5b7213daa358ce74d154352657353a Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 24 Jan 2013 10:31:28 +0800 Subject: usb: Using correct way to clear usb3.0 device's remote wakeup feature. Usb3.0 device defines function remote wakeup which is only for interface recipient rather than device recipient. This is different with usb2.0 device's remote wakeup feature which is defined for device recipient. According usb3.0 spec 9.4.5, the function remote wakeup can be modified by the SetFeature() requests using the FUNCTION_SUSPEND feature selector. This patch is to use correct way to disable usb3.0 device's function remote wakeup after suspend error and resuming. This should be backported to kernels as old as 3.4, that contain the commit 623bef9e03a60adc623b09673297ca7a1cdfb367 "USB/xhci: Enable remote wakeup for USB3 devices." Signed-off-by: Lan Tianyu Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/core/hub.c | 70 ++++++++++++++++++++++++++++++++------------ include/uapi/linux/usb/ch9.h | 6 ++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 957ed2c41482..cbf7168e3ce7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2838,6 +2838,23 @@ void usb_enable_ltm(struct usb_device *udev) EXPORT_SYMBOL_GPL(usb_enable_ltm); #ifdef CONFIG_USB_SUSPEND +/* + * usb_disable_function_remotewakeup - disable usb3.0 + * device's function remote wakeup + * @udev: target device + * + * Assume there's only one function on the USB 3.0 + * device and disable remote wake for the first + * interface. FIXME if the interface association + * descriptor shows there's more than one function. + */ +static int usb_disable_function_remotewakeup(struct usb_device *udev) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE, + USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); +} /* * usb_port_suspend - suspend a usb device's upstream port @@ -2955,12 +2972,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); /* paranoia: "should not happen" */ - if (udev->do_remote_wakeup) - (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); + if (udev->do_remote_wakeup) { + if (!hub_is_superspeed(hub->hdev)) { + (void) usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else + (void) usb_disable_function_remotewakeup(udev); + + } /* Try to enable USB2 hardware LPM again */ if (udev->usb2_hw_lpm_capable == 1) @@ -3052,20 +3076,30 @@ static int finish_port_resume(struct usb_device *udev) * udev->reset_resume */ } else if (udev->actconfig && !udev->reset_resume) { - le16_to_cpus(&devstatus); - if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, + if (!hub_is_superspeed(udev->parent)) { + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (status) - dev_dbg(&udev->dev, - "disable remote wakeup, status %d\n", - status); + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + status = usb_get_status(udev, USB_RECIP_INTERFACE, 0, + &devstatus); + le16_to_cpus(&devstatus); + if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP + | USB_INTRF_STAT_FUNC_RW)) + status = + usb_disable_function_remotewakeup(udev); } + + if (status) + dev_dbg(&udev->dev, + "disable remote wakeup, status %d\n", + status); status = 0; } return status; diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index 50598472dc41..f738e25377ff 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -152,6 +152,12 @@ #define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0)) #define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1)) +/* + * Interface status, Figure 9-5 USB 3.0 spec + */ +#define USB_INTRF_STAT_FUNC_RW_CAP 1 +#define USB_INTRF_STAT_FUNC_RW 2 + #define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */ -- cgit v1.2.3-59-g8ed1b From ce4a3d52888a95473914bd54bcf6c566014fc03e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 5 Jan 2013 08:52:12 -0300 Subject: [media] radio: set vfl_dir correctly to fix modulator regression The vfl_dir field should be set to indicate whether a device can receive data, output data or can do both. This is used to let the v4l core know which ioctls should be accepted and which can be refused. Unfortunately, when this field was added the radio modulator drivers were not updated: radio modulators transmit and so vfl_dir should be set to VFL_DIR_TX (or VFL_DIR_M2M in the special case of wl128x). Because of this omission it is not possible to call g/s_modulator for these drivers, which effectively renders them useless. This patch sets the correct vfl_dir value for these drivers, correcting this bug. Thanks to Paul Grinberg for bringing this to my attention. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-keene.c | 1 + drivers/media/radio/radio-si4713.c | 1 + drivers/media/radio/radio-wl1273.c | 1 + drivers/media/radio/wl128x/fmdrv_v4l2.c | 10 ++++++++++ 4 files changed, 13 insertions(+) diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index e10e525f33e5..296941a9ae25 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -374,6 +374,7 @@ static int usb_keene_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_keene_ioctl_ops; radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; + radio->vdev.vfl_dir = VFL_DIR_TX; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index a082e400ed0f..1507c9d508d7 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -250,6 +250,7 @@ static struct video_device radio_si4713_vdev_template = { .name = "radio-si4713", .release = video_device_release, .ioctl_ops = &radio_si4713_ioctl_ops, + .vfl_dir = VFL_DIR_TX, }; /* Platform driver interface */ diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index c48be195bbad..cabbe3adf435 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1971,6 +1971,7 @@ static struct video_device wl1273_viddev_template = { .ioctl_ops = &wl1273_ioctl_ops, .name = WL1273_FM_DRIVER_NAME, .release = wl1273_vdev_release, + .vfl_dir = VFL_DIR_TX, }; static int wl1273_fm_radio_remove(struct platform_device *pdev) diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 048de4536036..0a8ee8fab924 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -518,6 +518,16 @@ static struct video_device fm_viddev_template = { .ioctl_ops = &fm_drv_ioctl_ops, .name = FM_DRV_NAME, .release = video_device_release, + /* + * To ensure both the tuner and modulator ioctls are accessible we + * set the vfl_dir to M2M to indicate this. + * + * It is not really a mem2mem device of course, but it can both receive + * and transmit using the same radio device. It's the only radio driver + * that does this and it should really be split in two radio devices, + * but that would affect applications using this driver. + */ + .vfl_dir = VFL_DIR_M2M, }; int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) -- cgit v1.2.3-59-g8ed1b From aa7f67304d1a03180f463258aa6f15a8b434e77d Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Mon, 14 Jan 2013 11:55:31 -0600 Subject: sched/rt: Use root_domain of rt_rq not current processor When the system has multiple domains do_sched_rt_period_timer() can run on any CPU and may iterate over all rt_rq in cpu_online_mask. This means when balance_runtime() is run for a given rt_rq that rt_rq may be in a different rd than the current processor. Thus if we use smp_processor_id() to get rd in do_balance_runtime() we may borrow runtime from a rt_rq that is not part of our rd. This changes do_balance_runtime to get the rd from the passed in rt_rq ensuring that we borrow runtime only from the correct rd for the given rt_rq. This fixes a BUG at kernel/sched/rt.c:687! in __disable_runtime when we try reclaim runtime lent to other rt_rq but runtime has been lent to a rt_rq in another rd. Signed-off-by: Shawn Bohrer Acked-by: Steven Rostedt Acked-by: Mike Galbraith Cc: peterz@infradead.org Cc: Link: http://lkml.kernel.org/r/1358186131-29494-1-git-send-email-sbohrer@rgmadvisors.com Signed-off-by: Ingo Molnar --- kernel/sched/rt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 418feb01344e..4f02b2847357 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -566,7 +566,7 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq) static int do_balance_runtime(struct rt_rq *rt_rq) { struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd; int i, weight, more = 0; u64 rt_period; -- cgit v1.2.3-59-g8ed1b From 38dc3348e36d6cbe6ad51d771e4db948cda5b0e3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 25 Jan 2013 14:14:22 +0000 Subject: sched: Fix warning in kernel/sched/fair.c a4c96ae319 "sched: Unthrottle rt runqueues in __disable_runtime()" turned the unthrottle_offline_cfs_rqs function into a static symbol, which now triggers a warning about it being potentially unused: kernel/sched/fair.c:2055:13: warning: 'unthrottle_offline_cfs_rqs' defined but not used [-Wunused-function] Marking it __maybe_unused shuts up the gcc warning and lets the compiler safely drop the function body when it's not being used. To reproduce, build the ARM bcm2835_defconfig. Signed-off-by: Arnd Bergmann Cc: Peter Boonstoppel Cc: Peter Zijlstra Cc: Paul Turner Cc: linux-arm-kernel@list.infradead.org Link: http://lkml.kernel.org/r/1359123276-15833-6-git-send-email-arnd@arndb.de Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5eea8707234a..81fa53643409 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2663,7 +2663,7 @@ static void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) hrtimer_cancel(&cfs_b->slack_timer); } -static void unthrottle_offline_cfs_rqs(struct rq *rq) +static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq) { struct cfs_rq *cfs_rq; -- cgit v1.2.3-59-g8ed1b From cff3c124a7e82ca0ea1d6864b27ef18c403c0773 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 25 Jan 2013 14:14:23 +0000 Subject: sched/debug: Fix format string for 32-bit platforms The type returned from atomic64_t can be either unsigned long or unsigned long long, depending on the architecture. Using a cast to unsigned long long lets us use the same format string for all architectures. Without this patch, building with scheduler debugging enabled results in: kernel/sched/debug.c: In function 'print_cfs_rq': kernel/sched/debug.c:225:2: warning: format '%ld' expects argument of type 'long int', but argument 4 has type 'long long int' [-Wformat] kernel/sched/debug.c:225:2: warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'long long int' [-Wformat] Signed-off-by: Arnd Bergmann Cc: Peter Zijlstra Cc: Paul Turner Cc: linux-arm-kernel@list.infradead.org Link: http://lkml.kernel.org/r/1359123276-15833-7-git-send-email-arnd@arndb.de Signed-off-by: Ingo Molnar --- kernel/sched/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 2cd3c1b4e582..7ae4c4c5420e 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -222,8 +222,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) cfs_rq->runnable_load_avg); SEQ_printf(m, " .%-30s: %lld\n", "blocked_load_avg", cfs_rq->blocked_load_avg); - SEQ_printf(m, " .%-30s: %ld\n", "tg_load_avg", - atomic64_read(&cfs_rq->tg->load_avg)); + SEQ_printf(m, " .%-30s: %lld\n", "tg_load_avg", + (unsigned long long)atomic64_read(&cfs_rq->tg->load_avg)); SEQ_printf(m, " .%-30s: %lld\n", "tg_load_contrib", cfs_rq->tg_load_contrib); SEQ_printf(m, " .%-30s: %d\n", "tg_runnable_contrib", -- cgit v1.2.3-59-g8ed1b From 55bcdce8a8228223ec4d17d8ded8134ed265d2c5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 16:52:45 -0500 Subject: USB: EHCI: remove ASS/PSS polling timeout This patch (as1647) attempts to work around a problem that seems to affect some nVidia EHCI controllers. They sometimes take a very long time to turn off their async or periodic schedules. I don't know if this is a result of other problems, but in any case it seems wise not to depend on schedule enables or disables taking effect in any specific length of time. The patch removes the existing 20-ms timeout for enabling and disabling the schedules. The driver will now continue to poll the schedule state at 1-ms intervals until the controller finally decides to obey the most recent command issued by the driver. Just in case this hides a problem, a debugging message will be logged if the controller takes longer than 20 polls. I don't know if this will actually fix anything, but it can't hurt. Signed-off-by: Alan Stern Tested-by: Piergiorgio Sartor CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 20dbdcbe9b0f..f904071d70df 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -113,14 +113,15 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci) if (want != actual) { - /* Poll again later, but give up after about 20 ms */ - if (ehci->ASS_poll_count++ < 20) { - ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); - return; - } - ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n", - want, actual); + /* Poll again later */ + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); + ++ehci->ASS_poll_count; + return; } + + if (ehci->ASS_poll_count > 20) + ehci_dbg(ehci, "ASS poll count reached %d\n", + ehci->ASS_poll_count); ehci->ASS_poll_count = 0; /* The status is up-to-date; restart or stop the schedule as needed */ @@ -159,14 +160,14 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) if (want != actual) { - /* Poll again later, but give up after about 20 ms */ - if (ehci->PSS_poll_count++ < 20) { - ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); - return; - } - ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n", - want, actual); + /* Poll again later */ + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); + return; } + + if (ehci->PSS_poll_count > 20) + ehci_dbg(ehci, "PSS poll count reached %d\n", + ehci->PSS_poll_count); ehci->PSS_poll_count = 0; /* The status is up-to-date; restart or stop the schedule as needed */ -- cgit v1.2.3-59-g8ed1b From 6e0c3339a6f19d748f16091d0a05adeb1e1f822b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 16:54:22 -0500 Subject: USB: EHCI: unlink one async QH at a time This patch (as1648) fixes a regression affecting nVidia EHCI controllers. Evidently they don't like to have more than one async QH unlinked at a time. I can't imagine how they manage to mess it up, but at least one of them does. The patch changes the async unlink logic in two ways: Each time an IAA cycle is started, only the first QH on the async unlink list is handled (rather than all of them). Async QHs do not all get unlinked as soon as they have been empty for long enough. Instead, only the last one (i.e., the one that has been on the schedule the longest) is unlinked, and then only if no other unlinks are in progress at the time. This means that when multiple QHs are empty, they won't be unlinked as quickly as before. That's okay; it won't affect correct operation of the driver or add an excessive load. Multiple unlinks tend to be relatively rare in any case. Signed-off-by: Alan Stern Reported-and-tested-by: Piergiorgio Sartor Cc: stable # 3.6 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 50 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3d989028c836..fd252f0cfb3a 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1197,17 +1197,26 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested) if (ehci->async_iaa || ehci->async_unlinking) return; - /* Do all the waiting QHs at once */ - ehci->async_iaa = ehci->async_unlink; - ehci->async_unlink = NULL; - /* If the controller isn't running, we don't have to wait for it */ if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) { + + /* Do all the waiting QHs */ + ehci->async_iaa = ehci->async_unlink; + ehci->async_unlink = NULL; + if (!nested) /* Avoid recursion */ end_unlink_async(ehci); /* Otherwise start a new IAA cycle */ } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) { + struct ehci_qh *qh; + + /* Do only the first waiting QH (nVidia bug?) */ + qh = ehci->async_unlink; + ehci->async_iaa = qh; + ehci->async_unlink = qh->unlink_next; + qh->unlink_next = NULL; + /* Make sure the unlinks are all visible to the hardware */ wmb(); @@ -1255,34 +1264,35 @@ static void end_unlink_async(struct ehci_hcd *ehci) } } +static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh); + static void unlink_empty_async(struct ehci_hcd *ehci) { - struct ehci_qh *qh, *next; - bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); + struct ehci_qh *qh; + struct ehci_qh *qh_to_unlink = NULL; bool check_unlinks_later = false; + int count = 0; - /* Unlink all the async QHs that have been empty for a timer cycle */ - next = ehci->async->qh_next.qh; - while (next) { - qh = next; - next = qh->qh_next.qh; - + /* Find the last async QH which has been empty for a timer cycle */ + for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh) { if (list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED) { - if (!stopped && qh->unlink_cycle == - ehci->async_unlink_cycle) + ++count; + if (qh->unlink_cycle == ehci->async_unlink_cycle) check_unlinks_later = true; else - single_unlink_async(ehci, qh); + qh_to_unlink = qh; } } - /* Start a new IAA cycle if any QHs are waiting for it */ - if (ehci->async_unlink) - start_iaa_cycle(ehci, false); + /* If nothing else is being unlinked, unlink the last empty QH */ + if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) { + start_unlink_async(ehci, qh_to_unlink); + --count; + } - /* QHs that haven't been empty for long enough will be handled later */ - if (check_unlinks_later) { + /* Other QHs will be handled later */ + if (count > 0) { ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true); ++ehci->async_unlink_cycle; } -- cgit v1.2.3-59-g8ed1b From da0aa7169b97d90f4af39a9dc84d58bbe19d7e78 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 17:09:42 -0500 Subject: USB: add usb_hcd_{start,end}_port_resume This patch (as1649) adds a mechanism for host controller drivers to inform usbcore when they have begun or ended resume signalling on a particular root-hub port. The core will then make sure that the root hub does not get runtime-suspended while the port resume is going on. Since commit 596d789a211d134dc5f94d1e5957248c204ef850 (USB: set hub's default autosuspend delay as 0), the system tries to suspend hubs whenever they aren't in use. While a root-hub port is being resumed, the root hub does not appear to be in use. Attempted runtime suspends fail because of the ongoing port resume, but the PM core just keeps on trying over and over again. We want to prevent this wasteful effort. Signed-off-by: Alan Stern Tested-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 2 ++ include/linux/usb/hcd.h | 3 +++ 3 files changed, 49 insertions(+) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4225d5e72131..8e64adf8e4d5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1025,6 +1026,49 @@ static int register_root_hub(struct usb_hcd *hcd) return retval; } +/* + * usb_hcd_start_port_resume - a root-hub port is sending a resume signal + * @bus: the bus which the root hub belongs to + * @portnum: the port which is being resumed + * + * HCDs should call this function when they know that a resume signal is + * being sent to a root-hub port. The root hub will be prevented from + * going into autosuspend until usb_hcd_end_port_resume() is called. + * + * The bus's private lock must be held by the caller. + */ +void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum) +{ + unsigned bit = 1 << portnum; + + if (!(bus->resuming_ports & bit)) { + bus->resuming_ports |= bit; + pm_runtime_get_noresume(&bus->root_hub->dev); + } +} +EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume); + +/* + * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal + * @bus: the bus which the root hub belongs to + * @portnum: the port which is being resumed + * + * HCDs should call this function when they know that a resume signal has + * stopped being sent to a root-hub port. The root hub will be allowed to + * autosuspend again. + * + * The bus's private lock must be held by the caller. + */ +void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum) +{ + unsigned bit = 1 << portnum; + + if (bus->resuming_ports & bit) { + bus->resuming_ports &= ~bit; + pm_runtime_put_noidle(&bus->root_hub->dev); + } +} +EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume); /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb.h b/include/linux/usb.h index 689b14b26c8d..4d22d0f6167a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -357,6 +357,8 @@ struct usb_bus { int bandwidth_int_reqs; /* number of Interrupt requests */ int bandwidth_isoc_reqs; /* number of Isoc. requests */ + unsigned resuming_ports; /* bit array: resuming root-hub ports */ + #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 608050b2545f..0a78df5f6cfd 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -430,6 +430,9 @@ extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); extern void usb_wakeup_notification(struct usb_device *hdev, unsigned int portnum); +extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum); +extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum); + /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) #define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) -- cgit v1.2.3-59-g8ed1b From f292e7f9fb0e4bec68bbd83443407d6bb7922d36 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 17:09:49 -0500 Subject: USB: EHCI: notify usbcore about port resumes This patch (as1650) adds calls to the new usb_hcd_{start,end}_port_resume() functions to ehci-hcd. Now EHCI root hubs won't be runtime suspended while they are sending a resume signal to one of their ports. Signed-off-by: Alan Stern Tested-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 1 + drivers/usb/host/ehci-hub.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 09537b2f1002..b416a3fc9959 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -797,6 +797,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); set_bit(i, &ehci->resuming_ports); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); + usb_hcd_start_port_resume(&hcd->self, i); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); } } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4ccb97c0678f..f88be801d60c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -851,6 +851,7 @@ static int ehci_hub_control ( /* resume signaling for 20 msec */ ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); + usb_hcd_start_port_resume(&hcd->self, wIndex); /* check the port again */ mod_timer(&ehci_to_hcd(ehci)->rh_timer, ehci->reset_done[wIndex]); @@ -862,6 +863,7 @@ static int ehci_hub_control ( clear_bit(wIndex, &ehci->suspended_ports); set_bit(wIndex, &ehci->port_c_suspend); ehci->reset_done[wIndex] = 0; + usb_hcd_end_port_resume(&hcd->self, wIndex); /* stop resume signaling */ temp = ehci_readl(ehci, status_reg); @@ -950,6 +952,7 @@ static int ehci_hub_control ( ehci->reset_done[wIndex] = 0; if (temp & PORT_PE) set_bit(wIndex, &ehci->port_c_suspend); + usb_hcd_end_port_resume(&hcd->self, wIndex); } if (temp & PORT_OC) -- cgit v1.2.3-59-g8ed1b From 840008bb5162f029d5bc05959c7f51a3e8f9e0ff Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 17:09:55 -0500 Subject: USB: UHCI: notify usbcore about port resumes This patch (as1651) adds calls to the new usb_hcd_{start,end}_port_resume() functions to uhci-hcd. Now UHCI root hubs won't be runtime suspended while they are sending a resume signal to one of their ports. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hub.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 768d54295a20..15d13229ddbb 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -116,6 +116,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, } } clear_bit(port, &uhci->resuming_ports); + usb_hcd_end_port_resume(&uhci_to_hcd(uhci)->self, port); } /* Wait for the UHCI controller in HP's iLO2 server management chip. @@ -167,6 +168,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci) set_bit(port, &uhci->resuming_ports); uhci->ports_timeout = jiffies + msecs_to_jiffies(25); + usb_hcd_start_port_resume( + &uhci_to_hcd(uhci)->self, port); /* Make sure we see the port again * after the resuming period is over. */ -- cgit v1.2.3-59-g8ed1b From ee74290b7853db9d5fd64db70e5c175241c59fba Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 25 Jan 2013 17:17:43 -0500 Subject: USB: EHCI: fix timer bug affecting port resume This patch (as1652) fixes a long-standing bug in ehci-hcd. The driver relies on status polls to know when to stop port-resume signalling. It uses the root-hub status timer to schedule these status polls. But when the driver for the root hub is resumed, the timer is rescheduled to go off immediately -- before the port is ready. When this happens the timer does not get re-enabled, which prevents the port resume from finishing until some other event occurs. The symptom is that when a new device is plugged in, it doesn't get recognized or enumerated until lsusb is run or something else happens. The solution is to re-enable the root-hub status timer after every status poll while a port resume is in progress. This bug hasn't surfaced before now because we never used to try to suspend the root hub in the middle of a port resume (except by coincidence). Signed-off-by: Alan Stern Reported-and-tested-by: Norbert Preining Tested-by: Ming Lei Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index f88be801d60c..4d3b294f203e 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -649,7 +649,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) status = STS_PCD; } } - /* FIXME autosuspend idle root hubs */ + + /* If a resume is in progress, make sure it can finish */ + if (ehci->resuming_ports) + mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(25)); + spin_unlock_irqrestore (&ehci->lock, flags); return status ? retval : 0; } -- cgit v1.2.3-59-g8ed1b From 36a6f8c035760dcbd0c3acb4c2fd56268588a9cb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 25 Jan 2013 09:25:40 +0100 Subject: regulator: max8998: fix incorrect min_uV value for ldo10 Correct value for minimal voltage for ldo10 output is 950000 uV. This patch fixes the typo introduced by patch adf6178ad5552a7f2f742a8c85343c50 ("regulator: max8998: Use uV in voltage_map_desc"), what solves broken probe of max8998 in v3.8-rc4. Signed-off-by: Marek Szyprowski Cc: stable@vger.kernel.org Signed-off-by: Mark Brown --- drivers/regulator/max8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 1f0df4046b86..0a8dd1cbee6f 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -65,7 +65,7 @@ static const struct voltage_map_desc ldo9_voltage_map_desc = { .min = 2800000, .step = 100000, .max = 3100000, }; static const struct voltage_map_desc ldo10_voltage_map_desc = { - .min = 95000, .step = 50000, .max = 1300000, + .min = 950000, .step = 50000, .max = 1300000, }; static const struct voltage_map_desc ldo1213_voltage_map_desc = { .min = 800000, .step = 100000, .max = 3300000, -- cgit v1.2.3-59-g8ed1b From f40cbcb933367aa79fa881baff276b3a4566b563 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Jan 2013 10:20:29 +0800 Subject: regulator: max8907: Fix using wrong dev argument for calling of_regulator_match The dev parameter is the device requesting the data. In this case it should be &pdev->dev rather than pdev->dev.parent. The dev parameter is used to call devm_kzalloc in of_get_regulator_init_data(), which means this fixes a memory leak because the memory is allocated every time probe() is called, thus it should be freed when this driver is unloaded. Signed-off-by: Axel Lin Reviewed-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/regulator/max8907-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index d1a77512d83e..d40cf7fdb546 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -237,8 +237,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev) return -EINVAL; } - ret = of_regulator_match(pdev->dev.parent, regulators, - max8907_matches, + ret = of_regulator_match(&pdev->dev, regulators, max8907_matches, ARRAY_SIZE(max8907_matches)); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", -- cgit v1.2.3-59-g8ed1b From b19f57589854eef5f5d252e1b63e1f3a212da2ca Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Jan 2013 10:24:18 +0800 Subject: regulator: max77686: Fix using wrong dev argument at various places Use &pdev->dev rather than iodev->dev for dev_err(). Use &pdev->dev rather than iodev->dev for devm_kzalloc() and of_regulator_match(), this fixes memory leak. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/max77686.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index b85040caaea3..cca18a3c0294 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -379,9 +379,10 @@ static struct regulator_desc regulators[] = { }; #ifdef CONFIG_OF -static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, +static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, struct max77686_platform_data *pdata) { + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct device_node *pmic_np, *regulators_np; struct max77686_regulator_data *rdata; struct of_regulator_match rmatch; @@ -390,15 +391,15 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, pmic_np = iodev->dev->of_node; regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators"); if (!regulators_np) { - dev_err(iodev->dev, "could not find regulators sub-node\n"); + dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; } pdata->num_regulators = ARRAY_SIZE(regulators); - rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); if (!rdata) { - dev_err(iodev->dev, + dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); return -ENOMEM; } @@ -407,7 +408,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, rmatch.name = regulators[i].name; rmatch.init_data = NULL; rmatch.of_node = NULL; - of_regulator_match(iodev->dev, regulators_np, &rmatch, 1); + of_regulator_match(&pdev->dev, regulators_np, &rmatch, 1); rdata[i].initdata = rmatch.init_data; rdata[i].of_node = rmatch.of_node; } @@ -417,7 +418,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, return 0; } #else -static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, +static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, struct max77686_platform_data *pdata) { return 0; @@ -440,7 +441,7 @@ static int max77686_pmic_probe(struct platform_device *pdev) } if (iodev->dev->of_node) { - ret = max77686_pmic_dt_parse_pdata(iodev, pdata); + ret = max77686_pmic_dt_parse_pdata(pdev, pdata); if (ret) return ret; } -- cgit v1.2.3-59-g8ed1b From b4895e2ca58a67ebab11f4671cc301fef0eedeb7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Jan 2013 10:26:32 +0800 Subject: regulator: max8997: Fix using wrong dev argument at various places Use &pdev->dev rather than iodev->dev for dev_err(), dev_warn() and dev_info(). Use &pdev->dev rather than iodev->dev for devm_kzalloc() and of_get_regulator_init_data(), this fixes memory leak. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/max8997.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 02be7fcae32f..836908ce505e 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -934,7 +934,7 @@ static struct regulator_desc regulators[] = { }; #ifdef CONFIG_OF -static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev, +static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, struct max8997_platform_data *pdata, struct device_node *pmic_np) { @@ -944,7 +944,7 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev, gpio = of_get_named_gpio(pmic_np, "max8997,pmic-buck125-dvs-gpios", i); if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); + dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); return -EINVAL; } pdata->buck125_gpios[i] = gpio; @@ -952,22 +952,23 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev, return 0; } -static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, struct max8997_platform_data *pdata) { + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct device_node *pmic_np, *regulators_np, *reg_np; struct max8997_regulator_data *rdata; unsigned int i, dvs_voltage_nr = 1, ret; pmic_np = iodev->dev->of_node; if (!pmic_np) { - dev_err(iodev->dev, "could not find pmic sub-node\n"); + dev_err(&pdev->dev, "could not find pmic sub-node\n"); return -ENODEV; } regulators_np = of_find_node_by_name(pmic_np, "regulators"); if (!regulators_np) { - dev_err(iodev->dev, "could not find regulators sub-node\n"); + dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; } @@ -976,11 +977,10 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, for_each_child_of_node(regulators_np, reg_np) pdata->num_regulators++; - rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); if (!rdata) { - dev_err(iodev->dev, "could not allocate memory for " - "regulator data\n"); + dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); return -ENOMEM; } @@ -991,14 +991,14 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, break; if (i == ARRAY_SIZE(regulators)) { - dev_warn(iodev->dev, "don't know how to configure " - "regulator %s\n", reg_np->name); + dev_warn(&pdev->dev, "don't know how to configure regulator %s\n", + reg_np->name); continue; } rdata->id = i; - rdata->initdata = of_get_regulator_init_data( - iodev->dev, reg_np); + rdata->initdata = of_get_regulator_init_data(&pdev->dev, + reg_np); rdata->reg_node = reg_np; rdata++; } @@ -1014,7 +1014,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || pdata->buck5_gpiodvs) { - ret = max8997_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); + ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); if (ret) return -EINVAL; @@ -1025,8 +1025,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, } else { if (pdata->buck125_default_idx >= 8) { pdata->buck125_default_idx = 0; - dev_info(iodev->dev, "invalid value for " - "default dvs index, using 0 instead\n"); + dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n"); } } @@ -1040,28 +1039,28 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, if (of_property_read_u32_array(pmic_np, "max8997,pmic-buck1-dvs-voltage", pdata->buck1_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck1 voltages not specified\n"); + dev_err(&pdev->dev, "buck1 voltages not specified\n"); return -EINVAL; } if (of_property_read_u32_array(pmic_np, "max8997,pmic-buck2-dvs-voltage", pdata->buck2_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck2 voltages not specified\n"); + dev_err(&pdev->dev, "buck2 voltages not specified\n"); return -EINVAL; } if (of_property_read_u32_array(pmic_np, "max8997,pmic-buck5-dvs-voltage", pdata->buck5_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck5 voltages not specified\n"); + dev_err(&pdev->dev, "buck5 voltages not specified\n"); return -EINVAL; } return 0; } #else -static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev, +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, struct max8997_platform_data *pdata) { return 0; @@ -1085,7 +1084,7 @@ static int max8997_pmic_probe(struct platform_device *pdev) } if (iodev->dev->of_node) { - ret = max8997_pmic_dt_parse_pdata(iodev, pdata); + ret = max8997_pmic_dt_parse_pdata(pdev, pdata); if (ret) return ret; } -- cgit v1.2.3-59-g8ed1b From bb588820ef421c6098dca1fec29c3b347f1c8c19 Mon Sep 17 00:00:00 2001 From: Christopher Staite Date: Sat, 26 Jan 2013 11:10:58 -0500 Subject: drm/radeon: fix MC blackout on evergreen+ Force the crtc mem requests on/off immediately rather than waiting for the double buffered updates to kick in. Seems we miss the update in certain conditions. Also handle the DCE6 case. Signed-off-by: Christopher Staite Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4d0e60adbc6d..112da9b3c8ee 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1313,14 +1313,18 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { radeon_wait_for_vblank(rdev, i); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { radeon_wait_for_vblank(rdev, i); tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } /* wait for the next frame */ @@ -1378,11 +1382,15 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s if (ASIC_IS_DCE6(rdev)) { tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } /* wait for the next frame */ frame_count = radeon_get_vblank_counter(rdev, i); -- cgit v1.2.3-59-g8ed1b From 674a16f2b4724880d07389abbb95abf320b924aa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 27 Jan 2013 21:57:51 -0500 Subject: drm/radeon: add WAIT_UNTIL to the non-VM safe regs list for cayman/TN Newer versions of mesa emit this. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/reg_srcs/cayman | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index 0f656b111c15..a072fa8c46b0 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -1,5 +1,6 @@ cayman 0x9400 0x0000802C GRBM_GFX_INDEX +0x00008040 WAIT_UNTIL 0x000084FC CP_STRMOUT_CNTL 0x000085F0 CP_COHER_CNTL 0x000085F4 CP_COHER_SIZE -- cgit v1.2.3-59-g8ed1b From 93d7b7622c199f1be25ca8fe64b3cbf468ea49b9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 28 Jan 2013 14:25:42 +0800 Subject: Revert "ASoC: fsl: fix multiple definition of init_module" This reverts commit 25b8d31488a3fb3611651991969526b2ea475764. While the commit fixes multiple init_module definition error with module build, it breaks build when both imx-pcm-fiq and imx-pcm-dma are built in as below. LD sound/soc/fsl/snd-soc-fsl-ssi.o LD sound/soc/fsl/snd-soc-fsl-utils.o LD sound/soc/fsl/snd-soc-imx-ssi.o LD sound/soc/fsl/snd-soc-imx-audmux.o LD sound/soc/fsl/snd-soc-imx-pcm-fiq.o LD sound/soc/fsl/snd-soc-imx-pcm-dma.o LD sound/soc/fsl/snd-soc-eukrea-tlv320.o LD sound/soc/fsl/snd-soc-imx-sgtl5000.o LD sound/soc/fsl/snd-soc-imx-mc13783.o LD sound/soc/fsl/built-in.o sound/soc/fsl/snd-soc-imx-pcm-dma.o: In function `imx_pcm_free': imx-pcm.c:(.text+0x464): multiple definition of `imx_pcm_free' sound/soc/fsl/snd-soc-imx-pcm-fiq.o:imx-pcm-fiq.c:(.text+0x1a8): first defined here sound/soc/fsl/snd-soc-imx-pcm-dma.o: In function `snd_imx_pcm_mmap': imx-pcm.c:(.text+0x35c): multiple definition of `snd_imx_pcm_mmap' sound/soc/fsl/snd-soc-imx-pcm-fiq.o:imx-pcm-fiq.c:(.text+0xa0): first defined here sound/soc/fsl/snd-soc-imx-pcm-dma.o: In function `imx_pcm_new': imx-pcm.c:(.text+0x3dc): multiple definition of `imx_pcm_new' sound/soc/fsl/snd-soc-imx-pcm-fiq.o:imx-pcm-fiq.c:(.text+0x120): first defined here make[4]: *** [sound/soc/fsl/built-in.o] Error 1 Let's revert the commit and find a proper fix for multiple init_module definition error later. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 9 +++++++-- sound/soc/fsl/Makefile | 5 +---- sound/soc/fsl/imx-pcm.c | 3 +++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index a210c8d7b4bc..3b98159d9645 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -108,13 +108,18 @@ if SND_IMX_SOC config SND_SOC_IMX_SSI tristate -config SND_SOC_IMX_PCM_FIQ +config SND_SOC_IMX_PCM tristate + +config SND_SOC_IMX_PCM_FIQ + bool select FIQ + select SND_SOC_IMX_PCM config SND_SOC_IMX_PCM_DMA - tristate + bool select SND_SOC_DMAENGINE_PCM + select SND_SOC_IMX_PCM config SND_SOC_IMX_AUDMUX tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ec1457915d7c..afd34794db53 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -41,10 +41,7 @@ endif obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o -obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += snd-soc-imx-pcm-fiq.o -snd-soc-imx-pcm-fiq-y := imx-pcm-fiq.o imx-pcm.o -obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += snd-soc-imx-pcm-dma.o -snd-soc-imx-pcm-dma-y := imx-pcm-dma.o imx-pcm.o +obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c index 0c9f188ddc68..d5cd9eff3b48 100644 --- a/sound/soc/fsl/imx-pcm.c +++ b/sound/soc/fsl/imx-pcm.c @@ -31,6 +31,7 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); return ret; } +EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap); static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { @@ -79,6 +80,7 @@ int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) out: return ret; } +EXPORT_SYMBOL_GPL(imx_pcm_new); void imx_pcm_free(struct snd_pcm *pcm) { @@ -100,6 +102,7 @@ void imx_pcm_free(struct snd_pcm *pcm) buf->area = NULL; } } +EXPORT_SYMBOL_GPL(imx_pcm_free); MODULE_DESCRIPTION("Freescale i.MX PCM driver"); MODULE_AUTHOR("Sascha Hauer "); -- cgit v1.2.3-59-g8ed1b From 1927661b1748480692f1fa2c390fe031c86d862a Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 28 Jan 2013 14:25:43 +0800 Subject: ASoC: fsl: fix snd-soc-imx-pcm module build When building modules with CONFIG_SND_IMX_SOC=m in imx_v6_v7_defconfig, we will see the following link error. LD [M] sound/soc/fsl/snd-soc-fsl-ssi.o LD [M] sound/soc/fsl/snd-soc-fsl-utils.o LD [M] sound/soc/fsl/snd-soc-imx-ssi.o LD [M] sound/soc/fsl/snd-soc-imx-audmux.o LD [M] sound/soc/fsl/snd-soc-imx-pcm.o sound/soc/fsl/imx-pcm-dma.o: In function `init_module': imx-pcm-dma.c:(.init.text+0x0): multiple definition of `init_module' sound/soc/fsl/imx-pcm-fiq.o:imx-pcm-fiq.c:(.init.text+0x0): first defined here sound/soc/fsl/imx-pcm-dma.o: In function `cleanup_module': imx-pcm-dma.c:(.exit.text+0x0): multiple definition of `cleanup_module' sound/soc/fsl/imx-pcm-fiq.o:imx-pcm-fiq.c:(.exit.text+0x0): first defined here make[4]: *** [sound/soc/fsl/snd-soc-imx-pcm.o] Error 1 The module snd-soc-imx-pcm is designed to link imx-pcm.o with imx-pcm-dma.o or imx-pcm-fiq.o depending on if option SND_SOC_IMX_PCM_DMA or SND_SOC_IMX_PCM_FIQ is enabled. Both imx-pcm-dma and imx-pcm-fiq register their own module_platform_driver. However, these two options are not mutually exclusive and can be enabled together. And that's why we see above multiple init_module definition error. Instead of having both imx-pcm-dma and imx-pcm-fiq register their own platform_driver, we should do only once in imx-pcm.c. Using platform_device_id to distinguish between imx-pcm-dma and imx-pcm-fiq, we can run-time call imx-pcm-dma/fiq specific initialization in .probe hook to have module snd-soc-imx-pcm work for both cases. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-dma.c | 21 +-------------------- sound/soc/fsl/imx-pcm-fiq.c | 22 +--------------------- sound/soc/fsl/imx-pcm.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/fsl/imx-pcm.h | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+), 41 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index bf363d8d044a..500f8ce55d78 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -154,26 +154,7 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = { .pcm_free = imx_pcm_free, }; -static int imx_soc_platform_probe(struct platform_device *pdev) +int imx_pcm_dma_init(struct platform_device *pdev) { return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2); } - -static int imx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static struct platform_driver imx_pcm_driver = { - .driver = { - .name = "imx-pcm-audio", - .owner = THIS_MODULE, - }, - .probe = imx_soc_platform_probe, - .remove = imx_soc_platform_remove, -}; - -module_platform_driver(imx_pcm_driver); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-pcm-audio"); diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 5ec362ae4d01..920f945cb2f4 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -281,7 +281,7 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = { .pcm_free = imx_pcm_fiq_free, }; -static int imx_soc_platform_probe(struct platform_device *pdev) +int imx_pcm_fiq_init(struct platform_device *pdev) { struct imx_ssi *ssi = platform_get_drvdata(pdev); int ret; @@ -314,23 +314,3 @@ failed_register: return ret; } - -static int imx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; -} - -static struct platform_driver imx_pcm_driver = { - .driver = { - .name = "imx-fiq-pcm-audio", - .owner = THIS_MODULE, - }, - - .probe = imx_soc_platform_probe, - .remove = imx_soc_platform_remove, -}; - -module_platform_driver(imx_pcm_driver); - -MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c index d5cd9eff3b48..0d0625bfcb65 100644 --- a/sound/soc/fsl/imx-pcm.c +++ b/sound/soc/fsl/imx-pcm.c @@ -104,6 +104,38 @@ void imx_pcm_free(struct snd_pcm *pcm) } EXPORT_SYMBOL_GPL(imx_pcm_free); +static int imx_pcm_probe(struct platform_device *pdev) +{ + if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0) + return imx_pcm_fiq_init(pdev); + + return imx_pcm_dma_init(pdev); +} + +static int imx_pcm_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static struct platform_device_id imx_pcm_devtype[] = { + { .name = "imx-pcm-audio", }, + { .name = "imx-fiq-pcm-audio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, imx_pcm_devtype); + +static struct platform_driver imx_pcm_driver = { + .driver = { + .name = "imx-pcm", + .owner = THIS_MODULE, + }, + .id_table = imx_pcm_devtype, + .probe = imx_pcm_probe, + .remove = imx_pcm_remove, +}; +module_platform_driver(imx_pcm_driver); + MODULE_DESCRIPTION("Freescale i.MX PCM driver"); MODULE_AUTHOR("Sascha Hauer "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 83c0ed7d55c9..5ae13a13a353 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -30,4 +30,22 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); void imx_pcm_free(struct snd_pcm *pcm); +#ifdef CONFIG_SND_SOC_IMX_PCM_DMA +int imx_pcm_dma_init(struct platform_device *pdev); +#else +static inline int imx_pcm_dma_init(struct platform_device *pdev) +{ + return -ENODEV; +} +#endif + +#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ +int imx_pcm_fiq_init(struct platform_device *pdev); +#else +static inline int imx_pcm_fiq_init(struct platform_device *pdev) +{ + return -ENODEV; +} +#endif + #endif /* _IMX_PCM_H */ -- cgit v1.2.3-59-g8ed1b From 0e33e48ddc4402e890aaeeeacc95f730bf522098 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 22 Jan 2013 22:47:40 +0100 Subject: brcmsmac: fix tx status processing This issue was reported on the wireless list (see [1]) in which brcmsmac ran into a fatal error: [ 588.284074] brcmsmac bcma0:0: frameid != txh->TxFrameID [ 588.284098] brcmsmac bcma0:0: MI_TFS: fatal [ 588.284103] brcmsmac bcma0:0: wl0: fatal error, reinitializing [ 588.286208] ieee80211 phy0: Hardware restart was requested The tx status feedback is processed in a loop limiting the number of frames processed in one run. The code terminate processing when the limit is reached regardless the txstatus value read from the device register. When that status is is flagged as being valid it must be processed as the hardware will clear it after is has been read. Bisecting was done by Seth Forshee and showed following commit as the culprit: commit 57fe504817ccec9b6ac23e973d2925343bf1e3b6 Author: Piotr Haber Date: Wed Nov 28 21:44:07 2012 +0100 brcmsmac: fix bounds checking in tx/rx [1] http://www.spinics.net/lists/linux-wireless/msg101293.html Reported-by: Linus Torvalds Tested-by: Seth Forshee Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmsmac/main.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 17594de4199e..9f3d7e9f3bb5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -1027,7 +1027,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) static bool brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) { - bool morepending = false; struct bcma_device *core; struct tx_status txstatus, *txs; u32 s1, s2; @@ -1041,23 +1040,20 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs = &txstatus; core = wlc_hw->d11core; *fatal = false; - s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); - while (!(*fatal) - && (s1 & TXS_V)) { - /* !give others some time to run! */ - if (n >= max_tx_num) { - morepending = true; - break; - } + while (n < max_tx_num) { + s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); if (s1 == 0xffffffff) { brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); *fatal = true; return false; } - s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); + /* only process when valid */ + if (!(s1 & TXS_V)) + break; + s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); txs->status = s1 & TXS_STATUS_MASK; txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; txs->sequence = s2 & TXS_SEQ_MASK; @@ -1065,15 +1061,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs->lasttxtime = 0; *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); - - s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); + if (*fatal == true) + return false; n++; } - if (*fatal) - return false; - - return morepending; + return n >= max_tx_num; } static void brcms_c_tbtt(struct brcms_c_info *wlc) -- cgit v1.2.3-59-g8ed1b From 6b112decb777884e37d308554e22e0a4f5cdf44f Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sun, 27 Jan 2013 14:30:29 +0100 Subject: bcma: fix NAND flash validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/driver_chipcommon_nflash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c index dbda91e4dff5..1f0b83e18f68 100644 --- a/drivers/bcma/driver_chipcommon_nflash.c +++ b/drivers/bcma/driver_chipcommon_nflash.c @@ -21,7 +21,7 @@ int bcma_nflash_init(struct bcma_drv_cc *cc) struct bcma_bus *bus = cc->core->bus; if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 && - cc->core->id.rev != 0x38) { + cc->core->id.rev != 38) { bcma_err(bus, "NAND flash on unsupported board!\n"); return -ENOTSUPP; } -- cgit v1.2.3-59-g8ed1b From 0a06ad8e3a1cb5311b7dbafde45410aa1bce9d40 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 27 Jan 2013 16:24:25 -0600 Subject: rtlwifi: Fix the usage of the wrong variable in usb.c In routine _rtl_rx_pre_process(), skb_dequeue() is called to get an skb; however, the wrong variable name is used in subsequent calls. Reported-by: Guenter Roeck Signed-off-by: Larry Finger Cc: Guenter Roeck Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f2ecdeb3a90d..1535efda3d52 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -542,8 +542,8 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) WARN_ON(skb_queue_empty(&rx_queue)); while (!skb_queue_empty(&rx_queue)) { _skb = skb_dequeue(&rx_queue); - _rtl_usb_rx_process_agg(hw, skb); - ieee80211_rx_irqsafe(hw, skb); + _rtl_usb_rx_process_agg(hw, _skb); + ieee80211_rx_irqsafe(hw, _skb); } } -- cgit v1.2.3-59-g8ed1b From 2e727622ddd14e2cbbe4e756ad4fd1eca915b713 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:20 +0000 Subject: avr32: Provide dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit avr32/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Avr32 does not use dma_map_ops, hence it should implement them as inline stubs using dma_common_mmap() and dma_common_get_sgtable(). Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: Haavard Skinnemoen Acked-by: Hans-Christian Egtvedt Signed-off-by: Marek Szyprowski --- arch/avr32/include/asm/dma-mapping.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/avr32/include/asm/dma-mapping.h b/arch/avr32/include/asm/dma-mapping.h index aaf5199d8fcb..b3d18f9f3e8d 100644 --- a/arch/avr32/include/asm/dma-mapping.h +++ b/arch/avr32/include/asm/dma-mapping.h @@ -336,4 +336,14 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +/* drivers/base/dma-mapping.c */ +extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size); +extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size); + +#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s) +#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s) + #endif /* __ASM_AVR32_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From afbe21d8b3aedc9d9df0110eaad3d3a816db55ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:21 +0000 Subject: blackfin: Provide dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit blackfin/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Blackfin does not use dma_map_ops, hence it should implement them as inline stubs using dma_common_mmap() and dma_common_get_sgtable(). Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: uclinux-dist-devel@blackfin.uclinux.org Acked-by: Scott Jiang Signed-off-by: Marek Szyprowski --- arch/blackfin/include/asm/dma-mapping.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h index bbf461076a0a..054d9ec57d9d 100644 --- a/arch/blackfin/include/asm/dma-mapping.h +++ b/arch/blackfin/include/asm/dma-mapping.h @@ -154,4 +154,14 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size, _dma_sync((dma_addr_t)vaddr, size, dir); } +/* drivers/base/dma-mapping.c */ +extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size); +extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size); + +#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s) +#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s) + #endif /* _BLACKFIN_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From 18180651fd156f33be363b0c952efb4d29812b38 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:22 +0000 Subject: c6x: Provide dummy dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit c6x/allmodconfig (assumed): drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . C6x does not use dma_map_ops, hence it should implement them itself. For now, use dummy implementations that just return -EINVAL, until the API has been finalized. Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: linux-c6x-dev@linux-c6x.org Signed-off-by: Marek Szyprowski --- arch/c6x/include/asm/dma-mapping.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h index 3c694065030f..88bd0d899bdb 100644 --- a/arch/c6x/include/asm/dma-mapping.h +++ b/arch/c6x/include/asm/dma-mapping.h @@ -89,4 +89,19 @@ extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f)) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent((d), (s), (v), (h)) +/* Not supported for now */ +static inline int dma_mmap_coherent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + return -EINVAL; +} + +static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + return -EINVAL; +} + #endif /* _ASM_C6X_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From 063acebaf4795e57fd2c49d712a9179d8bfa9192 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:23 +0000 Subject: cris: Provide dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cris/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Cris does not use dma_map_ops, hence it should implement them as inline stubs using dma_common_mmap() and dma_common_get_sgtable(). Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: linux-cris-kernel@axis.com Acked-by: Jesper Nilsson Signed-off-by: Marek Szyprowski --- arch/cris/include/asm/dma-mapping.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/cris/include/asm/dma-mapping.h b/arch/cris/include/asm/dma-mapping.h index 8588b2ccf854..2f0f654f1b44 100644 --- a/arch/cris/include/asm/dma-mapping.h +++ b/arch/cris/include/asm/dma-mapping.h @@ -158,5 +158,15 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size, { } +/* drivers/base/dma-mapping.c */ +extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size); +extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size); + +#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s) +#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s) + #endif -- cgit v1.2.3-59-g8ed1b From 5fd381126e4b6da3f431527ffe95271875eec98e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:24 +0000 Subject: frv: Provide dummy dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit frv/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Frv does not use dma_map_ops, hence it should implement them itself. For now, use dummy implementations that just return -EINVAL, until the API has been finalized. Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: David Howells Signed-off-by: Marek Szyprowski --- arch/frv/include/asm/dma-mapping.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/frv/include/asm/dma-mapping.h b/arch/frv/include/asm/dma-mapping.h index dfb811002c64..1746a2b8e6e7 100644 --- a/arch/frv/include/asm/dma-mapping.h +++ b/arch/frv/include/asm/dma-mapping.h @@ -132,4 +132,19 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size, flush_write_buffers(); } +/* Not supported for now */ +static inline int dma_mmap_coherent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + return -EINVAL; +} + +static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + return -EINVAL; +} + #endif /* _ASM_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From 546eda4bcae047bf443d2cb449291416f49b14a1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:25 +0000 Subject: m68k: Provide dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m68k/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . M68k does not use dma_map_ops, hence it should implement them as inline stubs using dma_common_mmap() and dma_common_get_sgtable(). Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: linux-m68k@lists.linux-m68k.org Signed-off-by: Marek Szyprowski --- arch/m68k/include/asm/dma-mapping.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/m68k/include/asm/dma-mapping.h b/arch/m68k/include/asm/dma-mapping.h index 3e6b8445af6a..292805f0762e 100644 --- a/arch/m68k/include/asm/dma-mapping.h +++ b/arch/m68k/include/asm/dma-mapping.h @@ -115,4 +115,14 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t handle) #include #endif +/* drivers/base/dma-mapping.c */ +extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size); +extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size); + +#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s) +#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s) + #endif /* _M68K_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From 90582b2a6f14cfdf4b4208d7fe4f366493d977ea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:26 +0000 Subject: mn10300: Provide dummy dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mn10300/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Mn10300 does not use dma_map_ops, hence it should implement them itself. For now, use dummy implementations that just return -EINVAL, until the API has been finalized. Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: linux-am33-list@redhat.com Signed-off-by: Marek Szyprowski --- arch/mn10300/include/asm/dma-mapping.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/mn10300/include/asm/dma-mapping.h b/arch/mn10300/include/asm/dma-mapping.h index c1be4397b1ed..a18abfc558eb 100644 --- a/arch/mn10300/include/asm/dma-mapping.h +++ b/arch/mn10300/include/asm/dma-mapping.h @@ -168,4 +168,19 @@ void dma_cache_sync(void *vaddr, size_t size, mn10300_dcache_flush_inv(); } +/* Not supported for now */ +static inline int dma_mmap_coherent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + return -EINVAL; +} + +static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + return -EINVAL; +} + #endif -- cgit v1.2.3-59-g8ed1b From 59bb8407366b3c627e2c309e9f86d3c851e8362f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:27 +0000 Subject: parisc: Provide dummy dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit parisc/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Parisc does not use dma_map_ops, hence it should implement them itself. For now, use dummy implementations that just return -EINVAL, until the API has been finalized, as it cannot be supported on PA-RISC as-is. Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: James Bottomley Cc: linux-parisc@vger.kernel.org Signed-off-by: Marek Szyprowski --- arch/parisc/include/asm/dma-mapping.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index 467bbd510eac..106b395688e1 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -238,4 +238,19 @@ void * sba_get_iommu(struct parisc_device *dev); /* At the moment, we panic on error for IOMMU resource exaustion */ #define dma_mapping_error(dev, x) 0 +/* This API cannot be supported on PA-RISC */ +static inline int dma_mmap_coherent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + return -EINVAL; +} + +static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + return -EINVAL; +} + #endif -- cgit v1.2.3-59-g8ed1b From da57b936ea7b328d1009b37a0a0ad1f14148e104 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 27 Jan 2013 09:33:28 +0000 Subject: xtensa: Provide dummy dma_mmap_coherent() and dma_get_sgtable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xtensa/allmodconfig: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ For architectures using dma_map_ops, dma_mmap_coherent() and dma_get_sgtable() are provided in . Xtensa does not use dma_map_ops, hence it should implement them itself. For now, use dummy implementations that just return -EINVAL, until the API has been finalized. Signed-off-by: Geert Uytterhoeven Cc: Marek Szyprowski Cc: linux-xtensa@linux-xtensa.org Signed-off-by: Marek Szyprowski --- arch/xtensa/include/asm/dma-mapping.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 4acb5feba1fb..172a02a6ad14 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -170,4 +170,19 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size, consistent_sync(vaddr, size, direction); } +/* Not supported for now */ +static inline int dma_mmap_coherent(struct device *dev, + struct vm_area_struct *vma, void *cpu_addr, + dma_addr_t dma_addr, size_t size) +{ + return -EINVAL; +} + +static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + return -EINVAL; +} + #endif /* _XTENSA_DMA_MAPPING_H */ -- cgit v1.2.3-59-g8ed1b From 80d84ef3ff1ddc7a829c58980a9dd566a8af5203 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Tue, 22 Jan 2013 05:13:48 +0000 Subject: l2tp: prevent l2tp_tunnel_delete racing with userspace close If a tunnel socket is created by userspace, l2tp hooks the socket destructor in order to clean up resources if userspace closes the socket or crashes. It also caches a pointer to the struct sock for use in the data path and in the netlink interface. While it is safe to use the cached sock pointer in the data path, where the skb references keep the socket alive, it is not safe to use it elsewhere as such access introduces a race with userspace closing the socket. In particular, l2tp_tunnel_delete is prone to oopsing if a multithreaded userspace application closes a socket at the same time as sending a netlink delete command for the tunnel. This patch fixes this oops by forcing l2tp_tunnel_delete to explicitly look up a tunnel socket held by userspace using sockfd_lookup(). Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 76 ++++++++++++++++++++++++++++++++++++++++++++-------- net/l2tp/l2tp_core.h | 5 +++- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 1a9f3723c13c..06389d5ff120 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -168,6 +168,51 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) } +/* Lookup the tunnel socket, possibly involving the fs code if the socket is + * owned by userspace. A struct sock returned from this function must be + * released using l2tp_tunnel_sock_put once you're done with it. + */ +struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) +{ + int err = 0; + struct socket *sock = NULL; + struct sock *sk = NULL; + + if (!tunnel) + goto out; + + if (tunnel->fd >= 0) { + /* Socket is owned by userspace, who might be in the process + * of closing it. Look the socket up using the fd to ensure + * consistency. + */ + sock = sockfd_lookup(tunnel->fd, &err); + if (sock) + sk = sock->sk; + } else { + /* Socket is owned by kernelspace */ + sk = tunnel->sock; + } + +out: + return sk; +} +EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_lookup); + +/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ +void l2tp_tunnel_sock_put(struct sock *sk) +{ + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + if (tunnel) { + if (tunnel->fd >= 0) { + /* Socket is owned by userspace */ + sockfd_put(sk->sk_socket); + } + sock_put(sk); + } +} +EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put); + /* Lookup a session by id in the global session list */ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) @@ -1607,6 +1652,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 tunnel->old_sk_destruct = sk->sk_destruct; sk->sk_destruct = &l2tp_tunnel_destruct; tunnel->sock = sk; + tunnel->fd = fd; lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock"); sk->sk_allocation = GFP_ATOMIC; @@ -1642,24 +1688,32 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); */ int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) { - int err = 0; - struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL; + int err = -EBADF; + struct socket *sock = NULL; + struct sock *sk = NULL; + + sk = l2tp_tunnel_sock_lookup(tunnel); + if (!sk) + goto out; + + sock = sk->sk_socket; + BUG_ON(!sock); /* Force the tunnel socket to close. This will eventually * cause the tunnel to be deleted via the normal socket close * mechanisms when userspace closes the tunnel socket. */ - if (sock != NULL) { - err = inet_shutdown(sock, 2); + err = inet_shutdown(sock, 2); - /* If the tunnel's socket was created by the kernel, - * close the socket here since the socket was not - * created by userspace. - */ - if (sock->file == NULL) - err = inet_release(sock); - } + /* If the tunnel's socket was created by the kernel, + * close the socket here since the socket was not + * created by userspace. + */ + if (sock->file == NULL) + err = inet_release(sock); + l2tp_tunnel_sock_put(sk); +out: return err; } EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 56d583e083a7..e62204cad4fe 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -188,7 +188,8 @@ struct l2tp_tunnel { int (*recv_payload_hook)(struct sk_buff *skb); void (*old_sk_destruct)(struct sock *); struct sock *sock; /* Parent socket */ - int fd; + int fd; /* Parent fd, if tunnel socket + * was created by userspace */ uint8_t priv[0]; /* private data */ }; @@ -228,6 +229,8 @@ out: return tunnel; } +extern struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel); +extern void l2tp_tunnel_sock_put(struct sock *sk); extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); -- cgit v1.2.3-59-g8ed1b From a13d3104710184ecc43edc35a25ae8092058463f Mon Sep 17 00:00:00 2001 From: Johannes Naab Date: Wed, 23 Jan 2013 11:36:51 +0000 Subject: netem: fix delay calculation in rate extension The delay calculation with the rate extension introduces in v3.3 does not properly work, if other packets are still queued for transmission. For the delay calculation to work, both delay types (latency and delay introduces by rate limitation) have to be handled differently. The latency delay for a packet can overlap with the delay of other packets. The delay introduced by the rate however is separate, and can only start, once all other rate-introduced delays finished. Latency delay is from same distribution for each packet, rate delay depends on the packet size. .: latency delay -: rate delay x: additional delay we have to wait since another packet is currently transmitted .....---- Packet 1 .....xx------ Packet 2 .....------ Packet 3 ^^^^^ latency stacks ^^ rate delay doesn't stack ^^ latency stacks -----> time When a packet is enqueued, we first consider the latency delay. If other packets are already queued, we can reduce the latency delay until the last packet in the queue is send, however the latency delay cannot be <0, since this would mean that the rate is overcommitted. The new reference point is the time at which the last packet will be send. To find the time, when the packet should be send, the rate introduces delay has to be added on top of that. Signed-off-by: Johannes Naab Acked-by: Hagen Paul Pfeifer Signed-off-by: David S. Miller --- net/sched/sch_netem.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 298c0ddfb57e..3d2acc7a9c80 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -438,18 +438,18 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (q->rate) { struct sk_buff_head *list = &sch->q; - delay += packet_len_2_sched_time(skb->len, q); - if (!skb_queue_empty(list)) { /* - * Last packet in queue is reference point (now). - * First packet in queue is already in flight, - * calculate this time bonus and substract + * Last packet in queue is reference point (now), + * calculate this time bonus and subtract * from delay. */ - delay -= now - netem_skb_cb(skb_peek(list))->time_to_send; + delay -= netem_skb_cb(skb_peek_tail(list))->time_to_send - now; + delay = max_t(psched_tdiff_t, 0, delay); now = netem_skb_cb(skb_peek_tail(list))->time_to_send; } + + delay += packet_len_2_sched_time(skb->len, q); } cb->time_to_send = now + delay; -- cgit v1.2.3-59-g8ed1b From 604dfd6efc9b79bce432f2394791708d8e8f6efc Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 27 Jan 2013 21:14:08 +0000 Subject: pktgen: correctly handle failures when adding a device The return value of pktgen_add_device() is not checked, so even if we fail to add some device, for example, non-exist one, we still see "OK:...". This patch fixes it. After this patch, I got: # echo "add_device non-exist" > /proc/net/pktgen/kpktgend_0 -bash: echo: write error: No such device # cat /proc/net/pktgen/kpktgend_0 Running: Stopped: Result: ERROR: can not add device non-exist # echo "add_device eth0" > /proc/net/pktgen/kpktgend_0 # cat /proc/net/pktgen/kpktgend_0 Running: Stopped: eth0 Result: OK: add_device=eth0 (Candidate for -stable) Cc: David S. Miller Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/pktgen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b29dacf900f9..e6e1cbe863f5 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1781,10 +1781,13 @@ static ssize_t pktgen_thread_write(struct file *file, return -EFAULT; i += len; mutex_lock(&pktgen_thread_lock); - pktgen_add_device(t, f); + ret = pktgen_add_device(t, f); mutex_unlock(&pktgen_thread_lock); - ret = count; - sprintf(pg_result, "OK: add_device=%s", f); + if (!ret) { + ret = count; + sprintf(pg_result, "OK: add_device=%s", f); + } else + sprintf(pg_result, "ERROR: can not add device %s", f); goto out; } -- cgit v1.2.3-59-g8ed1b From af668b3c276d0f958a3aa46ef8ec47e2d5d333b3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 28 Jan 2013 00:38:02 +0000 Subject: tun: fix carrier on/off status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit c8d68e6be1c3b242f1c598595830890b65cea64a removed carrier off call from tun_detach since it's now called on queue disable and not only on tun close. This confuses userspace which used this flag to detect a free tun. To fix, put this back but under if (clean). Signed-off-by: Michael S. Tsirkin Tested-by: Jason Wang Acked-by: Jason Wang Tested-by: Toralf Förster Signed-off-by: David S. Miller --- drivers/net/tun.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index cc09b67c23bc..ffdb84474c47 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -439,10 +439,13 @@ static void __tun_detach(struct tun_file *tfile, bool clean) } if (clean) { - if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && - !(tun->flags & TUN_PERSIST)) - if (tun->dev->reg_state == NETREG_REGISTERED) + if (tun && tun->numqueues == 0 && tun->numdisabled == 0) { + netif_carrier_off(tun->dev); + + if (!(tun->flags & TUN_PERSIST) && + tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); + } BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags)); @@ -1658,10 +1661,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) device_create_file(&tun->dev->dev, &dev_attr_owner) || device_create_file(&tun->dev->dev, &dev_attr_group)) pr_err("Failed to create tun sysfs files\n"); - - netif_carrier_on(tun->dev); } + netif_carrier_on(tun->dev); + tun_debug(KERN_INFO, tun, "tun_set_iff\n"); if (ifr->ifr_flags & IFF_NO_PI) -- cgit v1.2.3-59-g8ed1b From 692a998b908ae4c612d95d1f5f5adae03eca2b79 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 28 Jan 2013 01:05:17 +0000 Subject: vhost_net: correct error handling in vhost_net_set_backend() Currently, when vhost_init_used() fails the sock refcnt and ubufs were leaked. Correct this by calling vhost_init_used() before assign ubufs and restore the oldsock when it fails. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index ebd08b21b234..d10ad6f8df7e 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -827,15 +827,16 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) r = PTR_ERR(ubufs); goto err_ubufs; } - oldubufs = vq->ubufs; - vq->ubufs = ubufs; + vhost_net_disable_vq(n, vq); rcu_assign_pointer(vq->private_data, sock); - vhost_net_enable_vq(n, vq); - r = vhost_init_used(vq); if (r) - goto err_vq; + goto err_used; + vhost_net_enable_vq(n, vq); + + oldubufs = vq->ubufs; + vq->ubufs = ubufs; n->tx_packets = 0; n->tx_zcopy_err = 0; @@ -859,6 +860,11 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) mutex_unlock(&n->dev.mutex); return 0; +err_used: + rcu_assign_pointer(vq->private_data, oldsock); + vhost_net_enable_vq(n, vq); + if (ubufs) + vhost_ubuf_put_and_wait(ubufs); err_ubufs: fput(sock->file); err_vq: -- cgit v1.2.3-59-g8ed1b From 2b8b328b61c799957a456a5a8dab8cc7dea68575 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 28 Jan 2013 01:05:18 +0000 Subject: vhost_net: handle polling errors when setting backend Currently, the polling errors were ignored, which can lead following issues: - vhost remove itself unconditionally from waitqueue when stopping the poll, this may crash the kernel since the previous attempt of starting may fail to add itself to the waitqueue - userspace may think the backend were successfully set even when the polling failed. Solve this by: - check poll->wqh before trying to remove from waitqueue - report polling errors in vhost_poll_start(), tx_poll_start(), the return value will be checked and returned when userspace want to set the backend After this fix, there still could be a polling failure after backend is set, it will addressed by the next patch. Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/vhost/net.c | 27 ++++++++++++++++++--------- drivers/vhost/vhost.c | 18 +++++++++++++++--- drivers/vhost/vhost.h | 2 +- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index d10ad6f8df7e..959b1cd89e6a 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -165,12 +165,16 @@ static void tx_poll_stop(struct vhost_net *net) } /* Caller must have TX VQ lock */ -static void tx_poll_start(struct vhost_net *net, struct socket *sock) +static int tx_poll_start(struct vhost_net *net, struct socket *sock) { + int ret; + if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED)) - return; - vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file); - net->tx_poll_state = VHOST_NET_POLL_STARTED; + return 0; + ret = vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file); + if (!ret) + net->tx_poll_state = VHOST_NET_POLL_STARTED; + return ret; } /* In case of DMA done not in order in lower device driver for some reason. @@ -642,20 +646,23 @@ static void vhost_net_disable_vq(struct vhost_net *n, vhost_poll_stop(n->poll + VHOST_NET_VQ_RX); } -static void vhost_net_enable_vq(struct vhost_net *n, +static int vhost_net_enable_vq(struct vhost_net *n, struct vhost_virtqueue *vq) { struct socket *sock; + int ret; sock = rcu_dereference_protected(vq->private_data, lockdep_is_held(&vq->mutex)); if (!sock) - return; + return 0; if (vq == n->vqs + VHOST_NET_VQ_TX) { n->tx_poll_state = VHOST_NET_POLL_STOPPED; - tx_poll_start(n, sock); + ret = tx_poll_start(n, sock); } else - vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file); + ret = vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file); + + return ret; } static struct socket *vhost_net_stop_vq(struct vhost_net *n, @@ -833,7 +840,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) r = vhost_init_used(vq); if (r) goto err_used; - vhost_net_enable_vq(n, vq); + r = vhost_net_enable_vq(n, vq); + if (r) + goto err_used; oldubufs = vq->ubufs; vq->ubufs = ubufs; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 34389f75fe65..9759249e6d90 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -77,26 +77,38 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, init_poll_funcptr(&poll->table, vhost_poll_func); poll->mask = mask; poll->dev = dev; + poll->wqh = NULL; vhost_work_init(&poll->work, fn); } /* Start polling a file. We add ourselves to file's wait queue. The caller must * keep a reference to a file until after vhost_poll_stop is called. */ -void vhost_poll_start(struct vhost_poll *poll, struct file *file) +int vhost_poll_start(struct vhost_poll *poll, struct file *file) { unsigned long mask; + int ret = 0; mask = file->f_op->poll(file, &poll->table); if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); + if (mask & POLLERR) { + if (poll->wqh) + remove_wait_queue(poll->wqh, &poll->wait); + ret = -EINVAL; + } + + return ret; } /* Stop polling a file. After this function returns, it becomes safe to drop the * file reference. You must also flush afterwards. */ void vhost_poll_stop(struct vhost_poll *poll) { - remove_wait_queue(poll->wqh, &poll->wait); + if (poll->wqh) { + remove_wait_queue(poll->wqh, &poll->wait); + poll->wqh = NULL; + } } static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work, @@ -792,7 +804,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) fput(filep); if (pollstart && vq->handle_kick) - vhost_poll_start(&vq->poll, vq->kick); + r = vhost_poll_start(&vq->poll, vq->kick); mutex_unlock(&vq->mutex); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 2639c58b23ab..17261e277c02 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -42,7 +42,7 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work); void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, unsigned long mask, struct vhost_dev *dev); -void vhost_poll_start(struct vhost_poll *poll, struct file *file); +int vhost_poll_start(struct vhost_poll *poll, struct file *file); void vhost_poll_stop(struct vhost_poll *poll); void vhost_poll_flush(struct vhost_poll *poll); void vhost_poll_queue(struct vhost_poll *poll); -- cgit v1.2.3-59-g8ed1b From 9e85722d58ca9d49d718929184492a1180bced3c Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 28 Jan 2013 01:05:19 +0000 Subject: tuntap: allow polling/writing/reading when detached We forbid polling, writing and reading when the file were detached, this may complex the user in several cases: - when guest pass some buffers to vhost/qemu and then disable some queues, host/qemu needs to do its own cleanup on those buffers which is complex sometimes. We can do this simply by allowing a user can still write to an disabled queue. Write to an disabled queue will cause the packet pass to the kernel and read will get nothing. - align the polling behavior with macvtap which never fails when the queue is created. This can simplify the polling errors handling of its user (e.g vhost) We can simply achieve this by don't assign NULL to tfile->tun when detached. Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/tun.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ffdb84474c47..2917a86f4c43 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -298,11 +298,12 @@ static void tun_flow_cleanup(unsigned long data) } static void tun_flow_update(struct tun_struct *tun, u32 rxhash, - u16 queue_index) + struct tun_file *tfile) { struct hlist_head *head; struct tun_flow_entry *e; unsigned long delay = tun->ageing_time; + u16 queue_index = tfile->queue_index; if (!rxhash) return; @@ -311,7 +312,9 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, rcu_read_lock(); - if (tun->numqueues == 1) + /* We may get a very small possibility of OOO during switching, not + * worth to optimize.*/ + if (tun->numqueues == 1 || tfile->detached) goto unlock; e = tun_flow_find(head, rxhash); @@ -411,21 +414,21 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun = rtnl_dereference(tfile->tun); - if (tun) { + if (tun && !tfile->detached) { u16 index = tfile->queue_index; BUG_ON(index >= tun->numqueues); dev = tun->dev; rcu_assign_pointer(tun->tfiles[index], tun->tfiles[tun->numqueues - 1]); - rcu_assign_pointer(tfile->tun, NULL); ntfile = rtnl_dereference(tun->tfiles[index]); ntfile->queue_index = index; --tun->numqueues; - if (clean) + if (clean) { + rcu_assign_pointer(tfile->tun, NULL); sock_put(&tfile->sk); - else + } else tun_disable_queue(tun, tfile); synchronize_net(); @@ -473,6 +476,10 @@ static void tun_detach_all(struct net_device *dev) rcu_assign_pointer(tfile->tun, NULL); --tun->numqueues; } + list_for_each_entry(tfile, &tun->disabled, next) { + wake_up_all(&tfile->wq.wait); + rcu_assign_pointer(tfile->tun, NULL); + } BUG_ON(tun->numqueues != 0); synchronize_net(); @@ -503,7 +510,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) goto out; err = -EINVAL; - if (rtnl_dereference(tfile->tun)) + if (rtnl_dereference(tfile->tun) && !tfile->detached) goto out; err = -EBUSY; @@ -1202,7 +1209,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, tun->dev->stats.rx_packets++; tun->dev->stats.rx_bytes += len; - tun_flow_update(tun, rxhash, tfile->queue_index); + tun_flow_update(tun, rxhash, tfile); return total_len; } @@ -1816,7 +1823,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) ret = tun_attach(tun, file); } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { tun = rtnl_dereference(tfile->tun); - if (!tun || !(tun->flags & TUN_TAP_MQ)) + if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached) ret = -EINVAL; else __tun_detach(tfile, false); -- cgit v1.2.3-59-g8ed1b From 00d3d51e9d8c983e237236a41863d138b7f77ff6 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Mon, 28 Jan 2013 04:17:01 +0000 Subject: be2net: Updating Module Author string and log message string to "Emulex Corporation" Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 8 ++++---- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 4eba17b83ba8..f1b3df167ff2 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -36,13 +36,13 @@ #define DRV_VER "4.4.161.0u" #define DRV_NAME "be2net" -#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" -#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" -#define OC_NAME "Emulex OneConnect 10Gbps NIC" +#define BE_NAME "Emulex BladeEngine2" +#define BE3_NAME "Emulex BladeEngine3" +#define OC_NAME "Emulex OneConnect" #define OC_NAME_BE OC_NAME "(be3)" #define OC_NAME_LANCER OC_NAME "(Lancer)" #define OC_NAME_SH OC_NAME "(Skyhawk)" -#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver" +#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver" #define BE_VENDOR_ID 0x19a2 #define EMULEX_VENDOR_ID 0x10df diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 5c995700e534..4d6f3c54427a 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -25,7 +25,7 @@ MODULE_VERSION(DRV_VER); MODULE_DEVICE_TABLE(pci, be_dev_ids); MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); -MODULE_AUTHOR("ServerEngines Corporation"); +MODULE_AUTHOR("Emulex Corporation"); MODULE_LICENSE("GPL"); static unsigned int num_vfs; -- cgit v1.2.3-59-g8ed1b From 5e98a36ed4bf6ea396170e3af0dd4fcbe51d772f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 28 Jan 2013 10:44:29 +0000 Subject: ipv6 addrconf: Fix interface identifiers of 802.15.4 devices. The "Universal/Local" (U/L) bit must be complmented according to RFC4944 and RFC2464. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 420e56326384..1b5d8cb9b123 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1660,6 +1660,7 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) if (dev->addr_len != IEEE802154_ADDR_LEN) return -1; memcpy(eui, dev->dev_addr, 8); + eui[0] ^= 2; return 0; } -- cgit v1.2.3-59-g8ed1b From 2aeef18d37aa8c0bfca169d4ede1790d972bf649 Mon Sep 17 00:00:00 2001 From: Nivedita Singhvi Date: Mon, 28 Jan 2013 17:52:37 +0000 Subject: tcp: Increment LISTENOVERFLOW and LISTENDROPS in tcp_v4_conn_request() We drop a connection request if the accept backlog is full and there are sufficient packets in the syn queue to warrant starting drops. Increment the appropriate counters so this isn't silent, for accurate stats and help in debugging. This patch assumes LINUX_MIB_LISTENDROPS is a superset of/includes the counter LINUX_MIB_LISTENOVERFLOWS. Signed-off-by: Nivedita Singhvi Acked-by: Vijay Subramanian Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 70b09ef2463b..629937d514eb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1500,8 +1500,11 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * clogging syn queue with openreqs with exponentially increasing * timeout. */ - if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) + if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); goto drop; + } req = inet_reqsk_alloc(&tcp_request_sock_ops); if (!req) -- cgit v1.2.3-59-g8ed1b From eb492f7443206711406a7c78cc12dee43e551f0c Mon Sep 17 00:00:00 2001 From: Milos Vyletel Date: Tue, 29 Jan 2013 09:59:00 +0000 Subject: bonding: unset primary slave via sysfs When bonding module is loaded with primary parameter and one decides to unset primary slave using sysfs these settings are not preserved during bond device restart. Primary slave is only unset once and it's not remembered in bond->params structure. Below is example of recreation. grep OPTS /etc/sysconfig/network-scripts/ifcfg-bond0 BONDING_OPTS="mode=active-backup miimon=100 primary=eth01" grep "Primary Slave" /proc/net/bonding/bond0 Primary Slave: eth01 (primary_reselect always) echo "" > /sys/class/net/bond0/bonding/primary grep "Primary Slave" /proc/net/bonding/bond0 Primary Slave: None sed -i -e 's/primary=eth01//' /etc/sysconfig/network-scripts/ifcfg-bond0 grep OPTS /etc/sysconfig/network-scripts/ifcfg-bond BONDING_OPTS="mode=active-backup miimon=100 " ifdown bond0 && ifup bond0 without patch: grep "Primary Slave" /proc/net/bonding/bond0 Primary Slave: eth01 (primary_reselect always) with patch: grep "Primary Slave" /proc/net/bonding/bond0 Primary Slave: None Reviewed-by: Jiri Pirko Signed-off-by: Milos Vyletel Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_sysfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1877ed7ca086..1c9e09fbdff8 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1053,6 +1053,7 @@ static ssize_t bonding_store_primary(struct device *d, pr_info("%s: Setting primary slave to None.\n", bond->dev->name); bond->primary_slave = NULL; + memset(bond->params.primary, 0, sizeof(bond->params.primary)); bond_select_active_slave(bond); goto out; } -- cgit v1.2.3-59-g8ed1b From 286003048aaef49b26bb9d93611dc69085e8982e Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Mon, 28 Jan 2013 00:43:48 +0000 Subject: e1000e: enable ECC on I217/I218 to catch packet buffer memory errors In rare instances, memory errors have been detected in the internal packet buffer memory on I217/I218 when stressed under certain environmental conditions. Enable Error Correcting Code (ECC) in hardware to catch both correctable and uncorrectable errors. Correctable errors will be handled by the hardware. Uncorrectable errors in the packet buffer will cause the packet to be received with an error indication in the buffer descriptor causing the packet to be discarded. If the uncorrectable error is in the descriptor itself, the hardware will stop and interrupt the driver indicating the error. The driver will then reset the hardware in order to clear the error and restart. Both types of errors will be accounted for in statistics counters. Signed-off-by: Bruce Allan Cc: # 3.5.x & 3.6.x Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/defines.h | 9 ++++++ drivers/net/ethernet/intel/e1000e/e1000.h | 2 ++ drivers/net/ethernet/intel/e1000e/ethtool.c | 2 ++ drivers/net/ethernet/intel/e1000e/hw.h | 1 + drivers/net/ethernet/intel/e1000e/ich8lan.c | 11 +++++++ drivers/net/ethernet/intel/e1000e/netdev.c | 46 +++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 02a12b69555f..4dab6fc265a2 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -232,6 +232,7 @@ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ #define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */ #define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */ +#define E1000_CTRL_MEHE 0x00080000 /* Memory Error Handling Enable */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ @@ -389,6 +390,12 @@ #define E1000_PBS_16K E1000_PBA_16K +/* Uncorrectable/correctable ECC Error counts and enable bits */ +#define E1000_PBECCSTS_CORR_ERR_CNT_MASK 0x000000FF +#define E1000_PBECCSTS_UNCORR_ERR_CNT_MASK 0x0000FF00 +#define E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT 8 +#define E1000_PBECCSTS_ECC_ENABLE 0x00010000 + #define IFS_MAX 80 #define IFS_MIN 40 #define IFS_RATIO 4 @@ -408,6 +415,7 @@ #define E1000_ICR_RXSEQ 0x00000008 /* Rx sequence error */ #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ +#define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */ #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ #define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ #define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ @@ -443,6 +451,7 @@ #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */ #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ +#define E1000_IMS_ECCER E1000_ICR_ECCER /* Uncorrectable ECC Error */ #define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ #define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ #define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 6782a2eea1bc..7e95f221d60b 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -309,6 +309,8 @@ struct e1000_adapter { struct napi_struct napi; + unsigned int uncorr_errors; /* uncorrectable ECC errors */ + unsigned int corr_errors; /* correctable ECC errors */ unsigned int restart_queue; u32 txd_cmd; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index f95bc6ee1c22..fd4772a2691c 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -108,6 +108,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = { E1000_STAT("dropped_smbus", stats.mgpdc), E1000_STAT("rx_dma_failed", rx_dma_failed), E1000_STAT("tx_dma_failed", tx_dma_failed), + E1000_STAT("uncorr_ecc_errors", uncorr_errors), + E1000_STAT("corr_ecc_errors", corr_errors), }; #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index cf217777586c..b88676ff3d86 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -77,6 +77,7 @@ enum e1e_registers { #define E1000_POEMB E1000_PHY_CTRL /* PHY OEM Bits */ E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */ E1000_PBS = 0x01008, /* Packet Buffer Size */ + E1000_PBECCSTS = 0x0100C, /* Packet Buffer ECC Status - RW */ E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 976336547607..24d9f61956f0 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -3624,6 +3624,17 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_ich8lan) reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); ew32(RFCTL, reg); + + /* Enable ECC on Lynxpoint */ + if (hw->mac.type == e1000_pch_lpt) { + reg = er32(PBECCSTS); + reg |= E1000_PBECCSTS_ECC_ENABLE; + ew32(PBECCSTS, reg); + + reg = er32(CTRL); + reg |= E1000_CTRL_MEHE; + ew32(CTRL, reg); + } } /** diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index fbf75fdca994..643c883dd795 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1678,6 +1678,23 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } + /* Reset on uncorrectable ECC error */ + if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) { + u32 pbeccsts = er32(PBECCSTS); + + adapter->corr_errors += + pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK; + adapter->uncorr_errors += + (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >> + E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT; + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); + + /* return immediately since reset is imminent */ + return IRQ_HANDLED; + } + if (napi_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; @@ -1741,6 +1758,23 @@ static irqreturn_t e1000_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } + /* Reset on uncorrectable ECC error */ + if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) { + u32 pbeccsts = er32(PBECCSTS); + + adapter->corr_errors += + pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK; + adapter->uncorr_errors += + (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >> + E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT; + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); + + /* return immediately since reset is imminent */ + return IRQ_HANDLED; + } + if (napi_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; @@ -2104,6 +2138,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); + } else if (hw->mac.type == e1000_pch_lpt) { + ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER); } else { ew32(IMS, IMS_ENABLE_MASK); } @@ -4251,6 +4287,16 @@ static void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.mgptc += er32(MGTPTC); adapter->stats.mgprc += er32(MGTPRC); adapter->stats.mgpdc += er32(MGTPDC); + + /* Correctable ECC Errors */ + if (hw->mac.type == e1000_pch_lpt) { + u32 pbeccsts = er32(PBECCSTS); + adapter->corr_errors += + pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK; + adapter->uncorr_errors += + (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >> + E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT; + } } /** -- cgit v1.2.3-59-g8ed1b From 6cdd20c380eb62eab757c5a6ccc90dac7ecd774b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 29 Jan 2013 16:15:45 -0500 Subject: vmxnet3: set carrier state properly on probe vmxnet3 fails to set netif_carrier_off on probe, meaning that when an interface is opened the __LINK_STATE_NOCARRIER bit is already cleared, and so /sys/class/net//operstate remains in the unknown state. Correct this by setting netif_carrier_off on probe, like other drivers do. Also, while we're at it, lets remove the netif_carrier_ok checks from the link_state_update function, as that check is atomically contained within the netif_carrier_[on|off] functions anyway Tested successfully by myself Signed-off-by: Neil Horman CC: "David S. Miller" CC: "VMware, Inc." CC: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index dc8913c6238c..12c6440d1649 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -154,8 +154,7 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue) if (ret & 1) { /* Link is up. */ printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n", adapter->netdev->name, adapter->link_speed); - if (!netif_carrier_ok(adapter->netdev)) - netif_carrier_on(adapter->netdev); + netif_carrier_on(adapter->netdev); if (affectTxQueue) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -165,8 +164,7 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue) } else { printk(KERN_INFO "%s: NIC Link is Down\n", adapter->netdev->name); - if (netif_carrier_ok(adapter->netdev)) - netif_carrier_off(adapter->netdev); + netif_carrier_off(adapter->netdev); if (affectTxQueue) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -3061,6 +3059,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); netif_set_real_num_rx_queues(adapter->netdev, adapter->num_rx_queues); + netif_carrier_off(netdev); err = register_netdev(netdev); if (err) { -- cgit v1.2.3-59-g8ed1b From 9200ee4941a6e5d1ec5df88982243686882dff3f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 29 Jan 2013 16:36:47 -0500 Subject: drm/radeon: add quirk for RV100 board vbios says external TMDS while the board is actually internal TMDS. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=60037 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_combios.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 33a56a09ff10..3e403bdda58f 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2470,6 +2470,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) 1), ATOM_DEVICE_CRT1_SUPPORT); } + /* RV100 board with external TDMS bit mis-set. + * Actually uses internal TMDS, clear the bit. + */ + if (dev->pdev->device == 0x5159 && + dev->pdev->subsystem_vendor == 0x1014 && + dev->pdev->subsystem_device == 0x029A) { + tmp &= ~(1 << 4); + } if ((tmp >> 4) & 0x1) { devices |= ATOM_DEVICE_DFP2_SUPPORT; radeon_add_legacy_encoder(dev, -- cgit v1.2.3-59-g8ed1b From 49df9fc9b9fd41e5749c5a9be2d2076328f75fc7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 29 Jan 2013 13:33:05 -0800 Subject: target: Fix zero-length INQUIRY additional sense code regression This patch fixes a minor regression introduced in v3.8-rc1 code where a zero-length INQUIRY was no longer returning the correct INVALID FIELD IN CDB additional sense code. This regression was introduced with the following commit: commit de103c93aff0bed0ae984274e5dc8b95899badab Author: Christoph Hellwig Date: Tue Nov 6 12:24:09 2012 -0800 target: pass sense_reason as a return value and this patch has been tested with the following zero-length CDB: sg_raw /dev/sdd 12 00 83 00 00 00 SCSI Status: Check Condition Sense Information: Fixed format, current; Sense key: Illegal Request Additional sense: Invalid field in cdb Cc: Christoph Hellwig Cc: Paolo Bonzini Cc: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_spc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 84f9e96e8ace..f8857d4eac66 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -641,11 +641,10 @@ spc_emulate_inquiry(struct se_cmd *cmd) out: rbuf = transport_kmap_data_sg(cmd); - if (!rbuf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); + if (rbuf) { + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); + } if (!ret) target_complete_cmd(cmd, GOOD); -- cgit v1.2.3-59-g8ed1b From cab9609b449ae5a6875d7d4cef32a814527a3baa Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 29 Jan 2013 14:10:01 -0800 Subject: target: Fix zero-length MODE_SENSE regression This patch fixes a regression introduced in v3.8-rc1 code where a zero-length MODE_SENSE was no longer returning GOOD status, but instead returning TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE to generate a CHECK_CONDITION status. This regression was introduced with the following commit: commit de103c93aff0bed0ae984274e5dc8b95899badab Author: Christoph Hellwig Date: Tue Nov 6 12:24:09 2012 -0800 target: pass sense_reason as a return value and this patch has been tested with the following zero-length CDB: sg_raw /dev/sdd 5a 00 0a 00 00 00 00 00 00 00 SCSI Status: Good Sense Information: sense buffer empty Cc: Christoph Hellwig Cc: Paolo Bonzini Cc: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_spc.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index f8857d4eac66..2d88f087d961 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -850,7 +850,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; - unsigned char *buf, *map_buf; + unsigned char buf[SE_MODE_PAGE_BUF], *rbuf; int type = dev->transport->get_device_type(dev); int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); bool dbd = !!(cdb[1] & 0x08); @@ -862,26 +862,8 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) int ret; int i; - map_buf = transport_kmap_data_sg(cmd); - if (!map_buf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - /* - * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we - * know we actually allocated a full page. Otherwise, if the - * data buffer is too small, allocate a temporary buffer so we - * don't have to worry about overruns in all our INQUIRY - * emulation handling. - */ - if (cmd->data_length < SE_MODE_PAGE_BUF && - (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { - buf = kzalloc(SE_MODE_PAGE_BUF, GFP_KERNEL); - if (!buf) { - transport_kunmap_data_sg(cmd); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - } else { - buf = map_buf; - } + memset(buf, 0, SE_MODE_PAGE_BUF); + /* * Skip over MODE DATA LENGTH + MEDIUM TYPE fields to byte 3 for * MODE_SENSE_10 and byte 2 for MODE_SENSE (6). @@ -933,8 +915,6 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) if (page == 0x3f) { if (subpage != 0x00 && subpage != 0xff) { pr_warn("MODE_SENSE: Invalid subpage code: 0x%02x\n", subpage); - kfree(buf); - transport_kunmap_data_sg(cmd); return TCM_INVALID_CDB_FIELD; } @@ -971,7 +951,6 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", page, subpage); - transport_kunmap_data_sg(cmd); return TCM_UNKNOWN_MODE_PAGE; set_length: @@ -980,12 +959,12 @@ set_length: else buf[0] = length - 1; - if (buf != map_buf) { - memcpy(map_buf, buf, cmd->data_length); - kfree(buf); + rbuf = transport_kmap_data_sg(cmd); + if (rbuf) { + memcpy(rbuf, buf, min_t(u32, SE_MODE_PAGE_BUF, cmd->data_length)); + transport_kunmap_data_sg(cmd); } - transport_kunmap_data_sg(cmd); target_complete_cmd(cmd, GOOD); return 0; } -- cgit v1.2.3-59-g8ed1b From 8b4b0dcbf70d10f3acd6a88fca0679ca711066e0 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 29 Jan 2013 14:18:00 -0800 Subject: target: Fix zero-length READ_CAPACITY_16 regression This patch fixes a regression introduced in v3.8-rc1 code where a zero-length READ_CAPACITY_16 was no longer returning GOOD status, but instead returning TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE to generate a CHECK_CONDITION status. This regression was introduced with the following commit: commit de103c93aff0bed0ae984274e5dc8b95899badab Author: Christoph Hellwig Date: Tue Nov 6 12:24:09 2012 -0800 target: pass sense_reason as a return value and this patch has been tested with the following zero-length CDB: sg_raw /dev/sdd 9e 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 SCSI Status: Good Sense Information: sense buffer empty Also, convert sbc_emulate_readcapacity() to follow the same method of handling transport_kmap_data_sg() return values, but we never expect a zero-length request here. Cc: Christoph Hellwig Cc: Paolo Bonzini Cc: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 26a6d183ccb1..a664c664a31a 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -58,11 +58,10 @@ sbc_emulate_readcapacity(struct se_cmd *cmd) buf[7] = dev->dev_attrib.block_size & 0xff; rbuf = transport_kmap_data_sg(cmd); - if (!rbuf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); + if (rbuf) { + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); + } target_complete_cmd(cmd, GOOD); return 0; @@ -97,11 +96,10 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) buf[14] = 0x80; rbuf = transport_kmap_data_sg(cmd); - if (!rbuf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); + if (rbuf) { + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); + } target_complete_cmd(cmd, GOOD); return 0; -- cgit v1.2.3-59-g8ed1b From a2f95c363701deba2205f81929b40222ea6f4f80 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 12:01:13 -0700 Subject: regulator: clear state each invocation of of_regulator_match of_regulator_match() saves some dynamcially allocated state into the match table that's passed to it. By implementation and not contract, for each match table entry, if non-NULL state is already present, of_regulator_match() will not overwrite it. of_regulator_match() is typically called each time a regulator is probe()d. This means it is called with the same match table over and over again if a regulator triggers deferred probe. This results in stale, kfree()d data being left in the match table from probe to probe, which causes a variety of crashes or use of invalid data. Explicitly free all output state from of_regulator_match() before generating new results in order to avoid this. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/of_regulator.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 6f684916fd79..66ca769287ab 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -120,6 +120,12 @@ int of_regulator_match(struct device *dev, struct device_node *node, if (!dev || !node) return -EINVAL; + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + match->init_data = NULL; + match->of_node = NULL; + } + for_each_child_of_node(node, child) { name = of_get_property(child, "regulator-compatible", NULL); -- cgit v1.2.3-59-g8ed1b From 78796ae17eacedcdcaaeb03ba73d2e532a4c8f83 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Mon, 28 Jan 2013 16:48:54 +0100 Subject: USB: qcserial: add Telit Gobi QDL device Add VID and PID for Telit Gobi QDL device Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index aa148c21ea40..24662547dc5b 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ + {DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */ /* Gobi 2000 devices */ {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ -- cgit v1.2.3-59-g8ed1b From 03eb466f276ceef9dcf023dc5474db02af68aad9 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Mon, 28 Jan 2013 16:47:10 +0100 Subject: USB: option: add support for Telit LE920 Add PID and special handling for Telit LE920 Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0d9dac9e7f93..384bb925faf4 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -242,6 +242,7 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_CC864_DUAL 0x1005 #define TELIT_PRODUCT_CC864_SINGLE 0x1006 #define TELIT_PRODUCT_DE910_DUAL 0x1010 +#define TELIT_PRODUCT_LE920 0x1200 /* ZTE PRODUCTS */ #define ZTE_VENDOR_ID 0x19d2 @@ -534,6 +535,11 @@ static const struct option_blacklist_info zte_1255_blacklist = { .reserved = BIT(3) | BIT(4), }; +static const struct option_blacklist_info telit_le920_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -784,6 +790,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), + .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, -- cgit v1.2.3-59-g8ed1b From f7eb97300832f4fe5fe916c5d84cd2e25169330e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 30 Jan 2013 13:57:40 -0500 Subject: drm/radeon: fix backend map setup on 1 RB sumo boards Need to adjust the backend map depending on which RB is enabled. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=892233 Reported-by: Mikko Tiihonen Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 112da9b3c8ee..2270867d8551 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2044,9 +2044,20 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(DMA_TILING_CONFIG, gb_addr_config); - tmp = gb_addr_config & NUM_PIPES_MASK; - tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends, - EVERGREEN_MAX_BACKENDS, disabled_rb_mask); + if ((rdev->config.evergreen.max_backends == 1) && + (rdev->flags & RADEON_IS_IGP)) { + if ((disabled_rb_mask & 3) == 1) { + /* RB0 disabled, RB1 enabled */ + tmp = 0x11111111; + } else { + /* RB1 disabled, RB0 enabled */ + tmp = 0x00000000; + } + } else { + tmp = gb_addr_config & NUM_PIPES_MASK; + tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends, + EVERGREEN_MAX_BACKENDS, disabled_rb_mask); + } WREG32(GB_BACKEND_MAP, tmp); WREG32(CGTS_SYS_TCC_DISABLE, 0); -- cgit v1.2.3-59-g8ed1b From f689e3acbd2e48cc4101e0af454193f81af4baaf Mon Sep 17 00:00:00 2001 From: Mikko Tiihonen Date: Wed, 30 Jan 2013 14:10:04 -0500 Subject: drm/radeon: protect against div by 0 in backend setup Make sure at least one RB is enabled in r6xx_remap_render_backend() to avoid an division by zero in some corner cases. See: https://bugzilla.redhat.com/show_bug.cgi?id=892233 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/r600.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index bc2540b17c5e..becb03e8b32f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1462,12 +1462,15 @@ u32 r6xx_remap_render_backend(struct radeon_device *rdev, u32 disabled_rb_mask) { u32 rendering_pipe_num, rb_num_width, req_rb_num; - u32 pipe_rb_ratio, pipe_rb_remain; + u32 pipe_rb_ratio, pipe_rb_remain, tmp; u32 data = 0, mask = 1 << (max_rb_num - 1); unsigned i, j; /* mask out the RBs that don't exist on that asic */ - disabled_rb_mask |= (0xff << max_rb_num) & 0xff; + tmp = disabled_rb_mask | ((0xff << max_rb_num) & 0xff); + /* make sure at least one RB is available */ + if ((tmp & 0xff) != 0xff) + disabled_rb_mask = tmp; rendering_pipe_num = 1 << tiling_pipe_num; req_rb_num = total_max_rb_num - r600_count_pipe_bits(disabled_rb_mask); -- cgit v1.2.3-59-g8ed1b From 8a7d7cbf7b5ff9912ef50b3e94c9ad9f37b1c75f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 29 Jan 2013 14:38:02 -0800 Subject: mwifiex: fix incomplete scan in case of IE parsing error A scan request is split into multiple scan commands queued in scan_pending_q. Each scan command will be sent to firmware and its response is handlded one after another. If any error is detected while parsing IE in command response buffer the remaining data will be ignored and error is returned. We should check if there is any more scan commands pending in the queue before returning error. This ensures that we will call cfg80211_scan_done if this is the last scan command, or send next scan command in scan_pending_q to firmware. Cc: "3.6+" Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/scan.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 9189a32b7844..973a9d90e9ea 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1563,7 +1563,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", scan_rsp->number_of_sets); ret = -1; - goto done; + goto check_next_scan; } bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); @@ -1634,7 +1634,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, if (!beacon_size || beacon_size > bytes_left) { bss_info += bytes_left; bytes_left = 0; - return -1; + ret = -1; + goto check_next_scan; } /* Initialize the current working beacon pointer for this BSS @@ -1690,7 +1691,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(priv->adapter->dev, "%s: bytes left < IE length\n", __func__); - goto done; + goto check_next_scan; } if (element_id == WLAN_EID_DS_PARAMS) { channel = *(current_ptr + sizeof(struct ieee_types_header)); @@ -1753,6 +1754,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } } +check_next_scan: spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (list_empty(&adapter->scan_pending_q)) { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1813,7 +1815,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } } -done: return ret; } -- cgit v1.2.3-59-g8ed1b From 70c37bf97f2a91accba76080db69144f3b69f736 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Mon, 28 Jan 2013 23:51:28 +0000 Subject: net: usbnet: prevent buggy devices from killing us MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A device sending 0 length frames as fast as it can has been observed killing the host system due to the resulting memory pressure. Temporarily disable RX skb allocation and URB submission when the current error ratio is high, preventing us from trying to allocate an infinite number of skbs. Reenable as soon as we are finished processing the done queue, allowing the device to continue working after short error bursts. Signed-off-by: Bjørn Mork Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 25 +++++++++++++++++++++++++ include/linux/usb/usbnet.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f34b2ebee815..977837725726 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -380,6 +380,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) unsigned long lockflags; size_t size = dev->rx_urb_size; + /* prevent rx skb allocation when error ratio is high */ + if (test_bit(EVENT_RX_KILL, &dev->flags)) { + usb_free_urb(urb); + return -ENOLINK; + } + skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); if (!skb) { netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); @@ -539,6 +545,17 @@ block: break; } + /* stop rx if packet error rate is high */ + if (++dev->pkt_cnt > 30) { + dev->pkt_cnt = 0; + dev->pkt_err = 0; + } else { + if (state == rx_cleanup) + dev->pkt_err++; + if (dev->pkt_err > 20) + set_bit(EVENT_RX_KILL, &dev->flags); + } + state = defer_bh(dev, skb, &dev->rxq, state); if (urb) { @@ -791,6 +808,11 @@ int usbnet_open (struct net_device *net) (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : "simple"); + /* reset rx error state */ + dev->pkt_cnt = 0; + dev->pkt_err = 0; + clear_bit(EVENT_RX_KILL, &dev->flags); + // delay posting reads until we're fully open tasklet_schedule (&dev->bh); if (info->manage_power) { @@ -1254,6 +1276,9 @@ static void usbnet_bh (unsigned long param) } } + /* restart RX again after disabling due to high error rate */ + clear_bit(EVENT_RX_KILL, &dev->flags); + // waiting for all pending urbs to complete? if (dev->wait) { if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 5de7a220e986..0de078d4cdb9 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -33,6 +33,7 @@ struct usbnet { wait_queue_head_t *wait; struct mutex phy_mutex; unsigned char suspend_count; + unsigned char pkt_cnt, pkt_err; /* i/o info: pipes etc */ unsigned in, out; @@ -70,6 +71,7 @@ struct usbnet { # define EVENT_DEV_OPEN 7 # define EVENT_DEVICE_REPORT_IDLE 8 # define EVENT_NO_RUNTIME_PM 9 +# define EVENT_RX_KILL 10 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) -- cgit v1.2.3-59-g8ed1b From bd30e947207e2ea0ff2c08f5b4a03025ddce48d3 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Tue, 29 Jan 2013 22:26:08 +0000 Subject: ipv6: do not create neighbor entries for local delivery They will be created at output, if ever needed. This avoids creating empty neighbor entries when TPROXYing/Forwarding packets for addresses that are not even directly reachable. Note that IPv4 already handles it this way. No neighbor entries are created for local input. Tested by myself and customer. Signed-off-by: Jiri Pirko Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e229a3bc345d..363d8b7772e8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -928,7 +928,7 @@ restart: dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); - if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!rt->n && !(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_LOCAL))) nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); else if (!(rt->dst.flags & DST_HOST)) nrt = rt6_alloc_clone(rt, &fl6->daddr); -- cgit v1.2.3-59-g8ed1b From 3d6d7ab5881b1d4431529410b949ba2e946f3b0f Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Wed, 30 Jan 2013 02:47:06 +0000 Subject: NET: qmi_wwan: add Telit LE920 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add VID, PID and fixed interface for Telit LE920 Signed-off-by: Daniele Palmas Acked-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 575a5839ee34..2ca7f8ea2dca 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -461,6 +461,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ + {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ -- cgit v1.2.3-59-g8ed1b From c76edd52bf19c9d01da7edc4ff04d3707c299779 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Wed, 30 Jan 2013 08:02:27 -0500 Subject: regulator: s2mps11: fix incorrect register for buck10 For BUCK10 the control registers are wrongly set as buck9 control register This patch corrects the control registers for buck10 Signed-off-by: Alim Akhtar Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/s2mps11.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index bd062a2ffbe2..cd9ea2ea1826 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -174,9 +174,9 @@ static struct regulator_ops s2mps11_buck_ops = { .min_uV = S2MPS11_BUCK_MIN2, \ .uV_step = S2MPS11_BUCK_STEP2, \ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ - .vsel_reg = S2MPS11_REG_B9CTRL2, \ + .vsel_reg = S2MPS11_REG_B10CTRL2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_B9CTRL1, \ + .enable_reg = S2MPS11_REG_B10CTRL1, \ .enable_mask = S2MPS11_ENABLE_MASK \ } -- cgit v1.2.3-59-g8ed1b From b09a61cc0bc2a7151f4ab652489e85253d5d0175 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Jan 2013 16:35:02 -0500 Subject: USB: EHCI: fix for leaking isochronous data This patch (as1653) fixes a bug in ehci-hcd. Unlike iTD entries, an siTD entry in the periodic schedule may not complete until the frame after the one it belongs to. Consequently, when scanning the periodic schedule it is necessary to start with the frame _preceding_ the one where the previous scan ended. Not doing this properly can result in memory leaks and failures to complete isochronous URBs. Signed-off-by: Alan Stern Reported-by: Andy Leiserson Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 69ebee73c0c1..2b6917dc3996 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -2212,11 +2212,11 @@ static void scan_isoc(struct ehci_hcd *ehci) } ehci->now_frame = now_frame; + frame = ehci->last_iso_frame; for (;;) { union ehci_shadow q, *q_p; __hc32 type, *hw_p; - frame = ehci->last_iso_frame; restart: /* scan each element in frame's queue for completions */ q_p = &ehci->pshadow [frame]; @@ -2321,6 +2321,9 @@ restart: /* Stop when we have reached the current frame */ if (frame == now_frame) break; - ehci->last_iso_frame = (frame + 1) & fmask; + + /* The last frame may still have active siTDs */ + ehci->last_iso_frame = frame; + frame = (frame + 1) & fmask; } } -- cgit v1.2.3-59-g8ed1b From 3e619d04159be54b3daa0b7036b0ce9e067f4b5d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Jan 2013 16:36:40 -0500 Subject: USB: EHCI: fix bug in scheduling periodic split transfers This patch (as1654) fixes a very old bug in ehci-hcd, connected with scheduling of periodic split transfers. The calculations for full/low-speed bus usage are all carried out after the correction for bit-stuffing has been applied, but the values in the max_tt_usecs array assume it hasn't been. The array should allow for allocation of up to 90% of the bus capacity, which is 900 us, not 780 us. The symptom caused by this bug is that any isochronous transfer to a full-speed device with a maxpacket size larger than about 980 bytes is always rejected with a -ENOSPC error. Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 2b6917dc3996..b476daf49f6f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -213,7 +213,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) } static const unsigned char -max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; +max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 }; /* carryover low/fullspeed bandwidth that crosses uframe boundries */ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) -- cgit v1.2.3-59-g8ed1b From 40a1ef95da85843696fc3ebe5fce39b0db32669f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 30 Jan 2013 07:55:53 +0000 Subject: x86-64: Replace left over sti/cli in ia32 audit exit code For some reason they didn't get replaced so far by their paravirt equivalents, resulting in code to be run with interrupts disabled that doesn't expect so (causing, in the observed case, a BUG_ON() to trigger) when syscall auditing is enabled. David (Cc-ed) came up with an identical fix, so likely this can be taken to count as an ack from him. Reported-by: Peter Moody Signed-off-by: Jan Beulich Cc: David Vrabel Cc: Konrad Rzeszutek Wilk Link: http://lkml.kernel.org/r/5108E01902000078000BA9C5@nat28.tlf.novell.com Signed-off-by: Ingo Molnar Cc: stable@vger.kernel.org Cc: Konrad Rzeszutek Wilk Cc: David Vrabel Tested-by: Peter Moody --- arch/x86/ia32/ia32entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 102ff7cb3e41..142c4ceff112 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -207,7 +207,7 @@ sysexit_from_sys_call: testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) jnz ia32_ret_from_sys_call TRACE_IRQS_ON - sti + ENABLE_INTERRUPTS(CLBR_NONE) movl %eax,%esi /* second arg, syscall return value */ cmpl $-MAX_ERRNO,%eax /* is it an error ? */ jbe 1f @@ -217,7 +217,7 @@ sysexit_from_sys_call: call __audit_syscall_exit movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */ movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi - cli + DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF testl %edi,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) jz \exit -- cgit v1.2.3-59-g8ed1b From 8de7f4da8ff8ad241a552512f727a47df15c5156 Mon Sep 17 00:00:00 2001 From: Luis Llorente Campo Date: Thu, 31 Jan 2013 13:37:05 +0100 Subject: USB: add OWL CM-160 support to cp210x driver This adds support for the OWL CM-160 electricity monitor to the cp210x driver. Signed-off-by: Luis Llorente Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index f14736f647ff..edc0f0dcad83 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ -- cgit v1.2.3-59-g8ed1b From ed39fadd6df01095378e499fac3674883f16b853 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 Jan 2013 09:00:52 -0500 Subject: drm/radeon/evergreen+: wait for the MC to settle after MC blackout Some chips seem to need a little delay after blacking out the MC before the requests actually stop. May fix: https://bugs.freedesktop.org/show_bug.cgi?id=56139 https://bugs.freedesktop.org/show_bug.cgi?id=57567 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 2270867d8551..a2d478e8692a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1349,6 +1349,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav blackout &= ~BLACKOUT_MODE_MASK; WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); } + /* wait for the MC to settle */ + udelay(100); } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) -- cgit v1.2.3-59-g8ed1b From 8cf9fa1240229cbdd888236c0c43fcbad680cf00 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 29 Jan 2013 10:44:23 -0600 Subject: Bluetooth: Fix handling of unexpected SMP PDUs The conn->smp_chan pointer can be NULL if SMP PDUs arrive at unexpected moments. To avoid NULL pointer dereferences the code should be checking for this and disconnect if an unexpected SMP PDU arrives. This patch fixes the issue by adding a check for conn->smp_chan for all other PDUs except pairing request and security request (which are are the first PDUs to come to initialize the SMP context). Signed-off-by: Johan Hedberg CC: stable@vger.kernel.org Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/smp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 68a9587c9694..5abefb12891d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -859,6 +859,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(code)); + /* + * The SMP context must be initialized for all other PDUs except + * pairing and security requests. If we get any other PDU when + * not initialized simply disconnect (done if this function + * returns an error). + */ + if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && + !conn->smp_chan) { + BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); + kfree_skb(skb); + return -ENOTSUPP; + } + switch (code) { case SMP_CMD_PAIRING_REQ: reason = smp_cmd_pairing_req(conn, skb); -- cgit v1.2.3-59-g8ed1b From 4c02e2d444595200d0b18b889994aac3611cd288 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 30 Jan 2013 11:50:55 -0300 Subject: Bluetooth: Fix hci_conn timeout routine If occurs a LE or SCO hci_conn timeout and the connection is already established (BT_CONNECTED state), the connection is not terminated as expected. This bug can be reproduced using l2test or scotest tool. Once the connection is established, kill l2test/scotest and the connection won't be terminated. This patch fixes hci_conn_disconnect helper so it is able to terminate LE and SCO connections, as well as ACL. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_conn.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 25bfce0666eb..4925a02ae7e4 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -249,12 +249,12 @@ static void hci_conn_disconnect(struct hci_conn *conn) __u8 reason = hci_proto_disconn_ind(conn); switch (conn->type) { - case ACL_LINK: - hci_acl_disconn(conn, reason); - break; case AMP_LINK: hci_amp_disconn(conn, reason); break; + default: + hci_acl_disconn(conn, reason); + break; } } -- cgit v1.2.3-59-g8ed1b From 73df66f8b1926c59cbc83000af6bf37ecc5509dd Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Thu, 31 Jan 2013 01:02:24 +0000 Subject: ipv6: rename datagram_send_ctl and datagram_recv_ctl The datagram_*_ctl functions in net/ipv6/datagram.c are IPv6-specific. Since datagram_send_ctl is publicly exported it should be appropriately named to reflect the fact that it's for IPv6 only. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- include/net/transp_v6.h | 22 +++++++++++----------- net/ipv6/datagram.c | 15 ++++++++------- net/ipv6/ip6_flowlabel.c | 4 ++-- net/ipv6/ipv6_sockglue.c | 6 +++--- net/ipv6/raw.c | 6 +++--- net/ipv6/udp.c | 6 +++--- net/l2tp/l2tp_ip6.c | 4 ++-- net/sunrpc/svcsock.c | 2 +- 8 files changed, 33 insertions(+), 32 deletions(-) diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 498433dd067d..938b7fd11204 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -34,17 +34,17 @@ extern int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern int datagram_recv_ctl(struct sock *sk, - struct msghdr *msg, - struct sk_buff *skb); - -extern int datagram_send_ctl(struct net *net, - struct sock *sk, - struct msghdr *msg, - struct flowi6 *fl6, - struct ipv6_txoptions *opt, - int *hlimit, int *tclass, - int *dontfrag); +extern int ip6_datagram_recv_ctl(struct sock *sk, + struct msghdr *msg, + struct sk_buff *skb); + +extern int ip6_datagram_send_ctl(struct net *net, + struct sock *sk, + struct msghdr *msg, + struct flowi6 *fl6, + struct ipv6_txoptions *opt, + int *hlimit, int *tclass, + int *dontfrag); #define LOOPBACK4_IPV6 cpu_to_be32(0x7f000006) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 8edf2601065a..06fd2730838b 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -380,7 +380,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) if (skb->protocol == htons(ETH_P_IPV6)) { sin->sin6_addr = ipv6_hdr(skb)->saddr; if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); + ip6_datagram_recv_ctl(sk, msg, skb); if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = IP6CB(skb)->iif; } else { @@ -468,7 +468,8 @@ out: } -int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) +int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb) { struct ipv6_pinfo *np = inet6_sk(sk); struct inet6_skb_parm *opt = IP6CB(skb); @@ -598,10 +599,10 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) return 0; } -int datagram_send_ctl(struct net *net, struct sock *sk, - struct msghdr *msg, struct flowi6 *fl6, - struct ipv6_txoptions *opt, - int *hlimit, int *tclass, int *dontfrag) +int ip6_datagram_send_ctl(struct net *net, struct sock *sk, + struct msghdr *msg, struct flowi6 *fl6, + struct ipv6_txoptions *opt, + int *hlimit, int *tclass, int *dontfrag) { struct in6_pktinfo *src_info; struct cmsghdr *cmsg; @@ -871,4 +872,4 @@ int datagram_send_ctl(struct net *net, struct sock *sk, exit_f: return err; } -EXPORT_SYMBOL_GPL(datagram_send_ctl); +EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl); diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 29124b7a04c8..d6de4b447250 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -365,8 +365,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, msg.msg_control = (void*)(fl->opt+1); memset(&flowi6, 0, sizeof(flowi6)); - err = datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, &junk, - &junk, &junk); + err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, + &junk, &junk, &junk); if (err) goto done; err = -EINVAL; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index ee94d31c9d4d..d1e2e8ef29c5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -476,8 +476,8 @@ sticky_done: msg.msg_controllen = optlen; msg.msg_control = (void*)(opt+1); - retv = datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, &junk, - &junk); + retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, + &junk, &junk); if (retv) goto done; update: @@ -1002,7 +1002,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, release_sock(sk); if (skb) { - int err = datagram_recv_ctl(sk, &msg, skb); + int err = ip6_datagram_recv_ctl(sk, &msg, skb); kfree_skb(skb); if (err) return err; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 6cd29b1e8b92..70fa81449997 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -507,7 +507,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, sock_recv_ts_and_drops(msg, sk, skb); if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); + ip6_datagram_recv_ctl(sk, msg, skb); err = copied; if (flags & MSG_TRUNC) @@ -822,8 +822,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(struct ipv6_txoptions); - err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, - &hlimit, &tclass, &dontfrag); + err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, + &hlimit, &tclass, &dontfrag); if (err < 0) { fl6_sock_release(flowlabel); return err; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index dfaa29b8b293..fb083295ff0b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -443,7 +443,7 @@ try_again: ip_cmsg_recv(msg, skb); } else { if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); + ip6_datagram_recv_ctl(sk, msg, skb); } err = copied; @@ -1153,8 +1153,8 @@ do_udp_sendmsg: memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(*opt); - err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, - &hlimit, &tclass, &dontfrag); + err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, + &hlimit, &tclass, &dontfrag); if (err < 0) { fl6_sock_release(flowlabel); return err; diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 927547171bc7..2316947ee772 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -554,8 +554,8 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(opt, 0, sizeof(struct ipv6_txoptions)); opt->tot_len = sizeof(struct ipv6_txoptions); - err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, - &hlimit, &tclass, &dontfrag); + err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, + &hlimit, &tclass, &dontfrag); if (err < 0) { fl6_sock_release(flowlabel); return err; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 0a148c9d2a5c..0f679df7d072 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -465,7 +465,7 @@ static int svc_udp_get_dest_address4(struct svc_rqst *rqstp, } /* - * See net/ipv6/datagram.c : datagram_recv_ctl + * See net/ipv6/datagram.c : ip6_datagram_recv_ctl */ static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, struct cmsghdr *cmh) -- cgit v1.2.3-59-g8ed1b From 8e72d37eb304d9ec5dfb51bc2d83e900b79ee764 Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Thu, 31 Jan 2013 01:02:25 +0000 Subject: ipv6: export ip6_datagram_recv_ctl ip6_datagram_recv_ctl and ip6_datagram_send_ctl are used for handling IPv6 ancillary data. Since ip6_datagram_send_ctl is already publicly exported for use in modules, ip6_datagram_recv_ctl should also be available to support ancillary data in the receive path. Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/ipv6/datagram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 06fd2730838b..7a778b9a7b85 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -598,6 +598,7 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, } return 0; } +EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg, struct flowi6 *fl6, -- cgit v1.2.3-59-g8ed1b From 700163db3de397a7557831e1eb9b8ce60e55590a Mon Sep 17 00:00:00 2001 From: Tom Parkin Date: Thu, 31 Jan 2013 01:02:26 +0000 Subject: l2tp: correctly handle ancillary data in the ip6 recv path l2tp_ip6 is incorrectly using the IPv4-specific ip_cmsg_recv to handle ancillary data. This means that socket options such as IPV6_RECVPKTINFO are not honoured in userspace. Convert l2tp_ip6 to use the IPv6-specific handler. Ref: net/ipv6/udp.c Signed-off-by: Tom Parkin Signed-off-by: James Chapman Signed-off-by: Chris Elston Signed-off-by: David S. Miller --- net/l2tp/l2tp_ip6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 2316947ee772..8ee4a86ae996 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -646,7 +646,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { - struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)msg->msg_name; size_t copied = 0; int err = -EOPNOTSUPP; @@ -688,8 +688,8 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, lsa->l2tp_scope_id = IP6CB(skb)->iif; } - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); + if (np->rxopt.all) + ip6_datagram_recv_ctl(sk, msg, skb); if (flags & MSG_TRUNC) copied = skb->len; -- cgit v1.2.3-59-g8ed1b From 66555e92fb7a619188c02cceae4bbc414f15f96d Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 31 Jan 2013 11:16:46 -0800 Subject: tcp: detect SYN/data drop when F-RTO is disabled On receiving the SYN-ACK, Fast Open checks icsk_retransmit for SYN retransmission to detect SYN/data drops. But if F-RTO is disabled, icsk_retransmit is reset at step D of tcp_fastretrans_alert() ( under tcp_ack()) before tcp_rcv_fastopen_synack(). The fix is to use total_retrans instead which accounts for SYN retransmission regardless the use of F-RTO. Signed-off-by: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 18f97ca76b00..8aca4ee95ff9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5649,8 +5649,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, * the remote receives only the retransmitted (regular) SYNs: either * the original SYN-data or the corresponding SYN-ACK is lost. */ - syn_drop = (cookie->len <= 0 && data && - inet_csk(sk)->icsk_retransmits); + syn_drop = (cookie->len <= 0 && data && tp->total_retrans); tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); -- cgit v1.2.3-59-g8ed1b From 71f1e45aa9974926c3eb511ac488119ed59d7a82 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 31 Jan 2013 13:12:29 +0200 Subject: tcm_vhost: fix pr_err on early kick It's OK to get kick before backend is set or after it is cleared, we can just ignore it. Signed-off-by: Michael S. Tsirkin Signed-off-by: Nicholas Bellinger --- drivers/vhost/tcm_vhost.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index b20df5c829f5..22321cf84fbe 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c @@ -575,10 +575,8 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs) /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ tv_tpg = vs->vs_tpg; - if (unlikely(!tv_tpg)) { - pr_err("%s endpoint not set\n", __func__); + if (unlikely(!tv_tpg)) return; - } mutex_lock(&vq->mutex); vhost_disable_notify(&vs->dev, vq); -- cgit v1.2.3-59-g8ed1b From 39dc9aabd8708944031e6307819b2a794b841f83 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 Jan 2013 09:01:59 -0500 Subject: drm/radeon/r5xx-r7xx: wait for the MC to settle after MC blackout Some chips seem to need a little delay after blacking out the MC before the requests actually stop. Stop DMAR errors reported by Shuah Khan. Reported-by: Shuah Khan Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/rv515.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 2bb6d0e84b3d..435ed3551364 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -336,6 +336,8 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) WREG32(R600_CITF_CNTL, blackout); } } + /* wait for the MC to settle */ + udelay(100); } void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) -- cgit v1.2.3-59-g8ed1b From f2d68cf4daa4de97d400d94836b907e35228e54f Mon Sep 17 00:00:00 2001 From: liu chuansheng Date: Thu, 31 Jan 2013 22:13:00 +0800 Subject: drm/radeon: Calling object_unrefer() when creating fb failure When kzalloc() failed in radeon_user_framebuffer_create(), need to call object_unreference() to match the object_reference(). Signed-off-by: liu chuansheng Signed-off-by: xueminsu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ff3def784619..05c96fa0b051 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1115,8 +1115,10 @@ radeon_user_framebuffer_create(struct drm_device *dev, } radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); - if (radeon_fb == NULL) + if (radeon_fb == NULL) { + drm_gem_object_unreference_unlocked(obj); return ERR_PTR(-ENOMEM); + } ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj); if (ret) { -- cgit v1.2.3-59-g8ed1b From fd5d93a0015ce1a7db881382022b2fcdfdc61760 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 30 Jan 2013 14:24:09 -0500 Subject: drm/radeon: prevent crash in the ring space allocation If the requested number of DWs on the ring is larger than the size of the ring itself, return an error. In testing with large VM updates, we've seen crashes when we try and allocate more space on the ring than the total size of the ring without checking. This prevents the crash but for large VM updates or bo moves of very large buffers, we will need to break the transaction down into multiple batches. I have patches to use IBs for the next kernel. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_ring.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 2430d80b1871..cd72062d5a91 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -377,6 +377,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi { int r; + /* make sure we aren't trying to allocate more space than there is on the ring */ + if (ndw > (ring->ring_size / 4)) + return -ENOMEM; /* Align requested size with padding so unlock_commit can * pad safely */ ndw = (ndw + ring->align_mask) & ~ring->align_mask; -- cgit v1.2.3-59-g8ed1b From 3646e4209f2bd0d09022ed792e594fb4f559b86c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 31 Jan 2013 16:19:19 -0500 Subject: drm/radeon: switch back to the CP ring for VM PT updates For large VM page table updates, we can sometimes generate more packets than there is space on the ring. This happens more readily with the DMA ring since it is 64K (vs 1M for the CP). For now, switch back to the CP. For the next kernel, I have a patch to utilize IBs for VM PT updates which alleviates this problem. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=58354 Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_asic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 9056fafb00ea..0b202c07fe50 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1445,7 +1445,7 @@ static struct radeon_asic cayman_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .pt_ring_index = R600_RING_TYPE_DMA_INDEX, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1572,7 +1572,7 @@ static struct radeon_asic trinity_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .pt_ring_index = R600_RING_TYPE_DMA_INDEX, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1699,7 +1699,7 @@ static struct radeon_asic si_asic = { .vm = { .init = &si_vm_init, .fini = &si_vm_fini, - .pt_ring_index = R600_RING_TYPE_DMA_INDEX, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &si_vm_set_page, }, .ring = { -- cgit v1.2.3-59-g8ed1b From faa06ab9aed22f0ad0e15bbf3f80463b5dd7cbe0 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 31 Jan 2013 14:56:12 -0800 Subject: target: Fix regression allowing unconfigured devices to fabric port link This patch fixes a v3.8-rc1 regression bug where an unconfigured se_device was incorrectly allowed to perform a fabric port-link. This bug was introduced in commit: commit 0fd97ccf45be26fb01b3a412f1f6c6b5044b2f16 Author: Christoph Hellwig Date: Mon Oct 8 00:03:19 2012 -0400 target: kill struct se_subsystem_dev which ended up dropping the original se_subsystem_dev->se_dev_ptr check preventing this from happening with pre commit 0fd97ccf code. Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_fabric_configfs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 810263dfa4a1..c57bbbc7a7d1 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -754,6 +754,11 @@ static int target_fabric_port_link( return -EFAULT; } + if (!(dev->dev_flags & DF_CONFIGURED)) { + pr_err("se_device not configured yet, cannot port link\n"); + return -ENODEV; + } + tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; se_tpg = container_of(to_config_group(tpg_ci), struct se_portal_group, tpg_group); -- cgit v1.2.3-59-g8ed1b From 7a3cf6ca1ab2a2f7161c6dec5a787fc7a5de864e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 31 Jan 2013 15:05:48 -0800 Subject: target: Fix divide by zero bug in fabric_max_sectors for unconfigured devices This patch fixes a possible divide by zero bug when the fabric_max_sectors device attribute is written and backend se_device failed to be successfully configured -> enabled. Go ahead and use block_size=512 within se_dev_set_fabric_max_sectors() in the event of a target_configure_device() failure case, as no valid dev->dev_attrib.block_size value will have been setup yet. Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e2695101bb99..f2aa7543d20a 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -941,6 +941,8 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) { + int block_size = dev->dev_attrib.block_size; + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device" " fabric_max_sectors while export_count is %d\n", @@ -978,8 +980,12 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) /* * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks() */ + if (!block_size) { + block_size = 512; + pr_warn("Defaulting to 512 for zero block_size\n"); + } fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors, - dev->dev_attrib.block_size); + block_size); dev->dev_attrib.fabric_max_sectors = fabric_max_sectors; pr_debug("dev[%p]: SE Device max_sectors changed to %u\n", -- cgit v1.2.3-59-g8ed1b From 972f7c832229781f09f03284cde484ccdb44d3ee Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 31 Jan 2013 20:23:49 -0800 Subject: x86, doc: Boot protocol 2.12 is in 3.8 The boot protocol 2.12 changes were pulled for 3.8, so update the documentation accordingly. Signed-off-by: H. Peter Anvin --- Documentation/x86/boot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 3edb4c2887a1..e540fd67f767 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -57,7 +57,7 @@ Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover protocol entry point. -Protocol 2.12: (Kernel 3.9) Added the xloadflags field and extension fields +Protocol 2.12: (Kernel 3.8) Added the xloadflags field and extension fields to struct boot_params for for loading bzImage and ramdisk above 4G in 64bit. -- cgit v1.2.3-59-g8ed1b From 7810cc1e7721220f1ed2a23ca95113d6434f6dcd Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 25 Jan 2013 16:54:20 +0200 Subject: digsig: Fix memory leakage in digsig_verify_rsa() digsig_verify_rsa() does not free kmalloc'ed buffer returned by mpi_get_buffer(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Dmitry Kasatkin Cc: stable@vger.kernel.org Signed-off-by: James Morris --- lib/digsig.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/digsig.c b/lib/digsig.c index 8c0e62975c88..dc2be7ed1765 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -162,6 +162,8 @@ static int digsig_verify_rsa(struct key *key, memset(out1, 0, head); memcpy(out1 + head, p, l); + kfree(p); + err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); if (err) goto err; -- cgit v1.2.3-59-g8ed1b From 2bd3bc4e8472424f1a6009825397639a8968920a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 13 Dec 2012 10:06:10 +0100 Subject: can: c_can: Set reserved bit in IFx_MASK2 to 1 on write According to C_CAN documentation, the reserved bit in IFx_MASK2 register is fixed 1. Cc: linux-stable Signed-off-by: Alexander Stein Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 58607f196c9e..2282b1ae9765 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -488,8 +488,12 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface, priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), IFX_WRITE_LOW_16BIT(mask)); + + /* According to C_CAN documentation, the reserved bit + * in IFx_MASK2 register is fixed 1 + */ priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), - IFX_WRITE_HIGH_16BIT(mask)); + IFX_WRITE_HIGH_16BIT(mask) | BIT(13)); priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), IFX_WRITE_LOW_16BIT(id)); -- cgit v1.2.3-59-g8ed1b From 3c911608085bf2d5a0822c418129f96a2a89d1b5 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 31 Jan 2013 00:55:02 +0000 Subject: btrfs: don't try to notify udev about missing devices If we remove a missing device, bdev is null, and if we send that off to btrfs_kobject_uevent we'll panic. Signed-off-by: Eric Sandeen Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/volumes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5cce6aa74012..485a5423e3c6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1556,7 +1556,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) ret = 0; /* Notify udev that device has changed */ - btrfs_kobject_uevent(bdev, KOBJ_CHANGE); + if (bdev) + btrfs_kobject_uevent(bdev, KOBJ_CHANGE); error_brelse: brelse(bh); -- cgit v1.2.3-59-g8ed1b From c249f911406efcc7456cb4af79396726bf7b8c57 Mon Sep 17 00:00:00 2001 From: Sven Killig Date: Fri, 1 Feb 2013 23:43:06 +0100 Subject: USB: ftdi_sio: add PID/VID entries for ELV WS 300 PC II Add PID/VID entries for ELV WS 300 PC II weather station Signed-off-by: Sven Killig Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ba68835d06a6..3ae3ff36e4aa 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -584,6 +584,7 @@ static struct usb_device_id id_table_combined [] = { /* * ELV devices: */ + { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index fa5d56038276..7c89cfcb85bb 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -204,7 +204,7 @@ /* * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). - * All of these devices use FTDI's vendor ID (0x0403). + * Almost all of these devices use FTDI's vendor ID (0x0403). * Further IDs taken from ELV Windows .inf file. * * The previously included PID for the UO 100 module was incorrect. @@ -212,6 +212,8 @@ * * Armin Laeuger originally sent the PID for the UM 100 module. */ +#define FTDI_ELV_VID 0x1B1F /* ELV AG */ +#define FTDI_ELV_WS300_PID 0xC006 /* eQ3 WS 300 PC II */ #define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ #define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ #define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ -- cgit v1.2.3-59-g8ed1b From d4fa681541aa7bf8570d03426dd7ba663a71c467 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 1 Feb 2013 12:06:51 +0100 Subject: USB: option: add Changhong CH690 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New device with 3 serial interfaces: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend) Sub=ff Prot=ff If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend) Sub=ff Prot=ff If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend) Sub=ff Prot=ff If#= 3 Alt= 0 #EPs= 2 Cls=08(stor) Sub=06 Prot=50 Cc: Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 384bb925faf4..567bc77d6397 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -454,6 +454,10 @@ static void option_instat_callback(struct urb *urb); #define TPLINK_VENDOR_ID 0x2357 #define TPLINK_PRODUCT_MA180 0x0201 +/* Changhong products */ +#define CHANGHONG_VENDOR_ID 0x2077 +#define CHANGHONG_PRODUCT_CH690 0x7001 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1326,6 +1330,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3-59-g8ed1b From 0ba3b2ccc72b3df5c305d61f59d93ab0f0e87991 Mon Sep 17 00:00:00 2001 From: Petr Kubánek Date: Fri, 1 Feb 2013 17:24:04 +0100 Subject: USB: ftdi_sio: add Zolix FTDI PID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Zolix Omni 1509 monochromator custom USB-RS232 converter. Signed-off-by: Petr Kubánek Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3ae3ff36e4aa..90ceef1776c3 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -671,6 +671,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 7c89cfcb85bb..9d359e189a64 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -147,6 +147,11 @@ #define XSENS_CONVERTER_6_PID 0xD38E #define XSENS_CONVERTER_7_PID 0xD38F +/** + * Zolix (www.zolix.com.cb) product ids + */ +#define FTDI_OMNI1509 0xD491 /* Omni1509 embedded USB-serial */ + /* * NDI (www.ndigital.com) product ids */ -- cgit v1.2.3-59-g8ed1b From 559bcac35facfed49ab4f408e162971612dcfdf3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 29 Jan 2013 22:58:04 -0500 Subject: via-rhine: Fix bugs in NAPI support. 1) rhine_tx() should use dev_kfree_skb() not dev_kfree_skb_irq() 2) rhine_slow_event_task's NAPI triggering logic is racey, it should just hit the interrupt mask register. This is the same as commit 7dbb491878a2c51d372a8890fa45a8ff80358af1 ("r8169: avoid NAPI scheduling delay.") made to fix the same problem in the r8169 driver. From Francois Romieu. Reported-by: Jamie Gloudon Tested-by: Jamie Gloudon Signed-off-by: David S. Miller --- drivers/net/ethernet/via/via-rhine.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 7992b3e05d3d..78ace59efd29 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1801,7 +1801,7 @@ static void rhine_tx(struct net_device *dev) rp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); } - dev_kfree_skb_irq(rp->tx_skbuff[entry]); + dev_kfree_skb(rp->tx_skbuff[entry]); rp->tx_skbuff[entry] = NULL; entry = (++rp->dirty_tx) % TX_RING_SIZE; } @@ -2010,11 +2010,7 @@ static void rhine_slow_event_task(struct work_struct *work) if (intr_status & IntrPCIErr) netif_warn(rp, hw, dev, "PCI error\n"); - napi_disable(&rp->napi); - rhine_irq_disable(rp); - /* Slow and safe. Consider __napi_schedule as a replacement ? */ - napi_enable(&rp->napi); - napi_schedule(&rp->napi); + iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable); out_unlock: mutex_unlock(&rp->task_lock); -- cgit v1.2.3-59-g8ed1b From 0231bb5336758426b44ccd798ccd3c5419c95d58 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Feb 2013 11:23:45 +0100 Subject: perf: Fix event group context move When we have group with mixed events (hw/sw) we want to end up with group leader being in hw context. So if group leader is initialy sw event, we move all the events under hw context. The move is done for each event by removing it from its context and adding it back into proper one. As a part of the removal the event is automatically disabled, which is not what we want at this stage of creating groups. The fix is to initialize event state after removal from sw context. This fix resulted from the following discussion: http://thread.gmane.org/gmane.linux.kernel.perf.user/1144 Reported-by: Andreas Hollmann Signed-off-by: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Link: http://lkml.kernel.org/r/1359714225-4231-1-git-send-email-jolsa@redhat.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 301079d06f24..7b6646a8c067 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -907,6 +907,15 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) ctx->nr_stat++; } +/* + * Initialize event state based on the perf_event_attr::disabled. + */ +static inline void perf_event__state_init(struct perf_event *event) +{ + event->state = event->attr.disabled ? PERF_EVENT_STATE_OFF : + PERF_EVENT_STATE_INACTIVE; +} + /* * Called at perf_event creation and when events are attached/detached from a * group. @@ -6179,8 +6188,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, event->overflow_handler = overflow_handler; event->overflow_handler_context = context; - if (attr->disabled) - event->state = PERF_EVENT_STATE_OFF; + perf_event__state_init(event); pmu = NULL; @@ -6609,9 +6617,17 @@ SYSCALL_DEFINE5(perf_event_open, mutex_lock(&gctx->mutex); perf_remove_from_context(group_leader); + + /* + * Removing from the context ends up with disabled + * event. What we want here is event in the initial + * startup state, ready to be add into new context. + */ + perf_event__state_init(group_leader); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { perf_remove_from_context(sibling); + perf_event__state_init(sibling); put_ctx(gctx); } mutex_unlock(&gctx->mutex); -- cgit v1.2.3-59-g8ed1b From 973ec449bb4f2b8c514bacbcb4d9506fc31c8ce3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 2 Feb 2013 05:23:16 +0000 Subject: tcp: fix an infinite loop in tcp_slow_start() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 9dc274151a548 (tcp: fix ABC in tcp_slow_start()), a nul snd_cwnd triggers an infinite loop in tcp_slow_start() Avoid this infinite loop and log a one time error for further analysis. FRTO code is suspected to cause this bug. Reported-by: Pasi Kärkkäinen Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_cong.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 291f2ed7cc31..cdf2e707bb10 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -310,6 +310,12 @@ void tcp_slow_start(struct tcp_sock *tp) { int cnt; /* increase in packets */ unsigned int delta = 0; + u32 snd_cwnd = tp->snd_cwnd; + + if (unlikely(!snd_cwnd)) { + pr_err_once("snd_cwnd is nul, please report this bug.\n"); + snd_cwnd = 1U; + } /* RFC3465: ABC Slow start * Increase only after a full MSS of bytes is acked @@ -324,7 +330,7 @@ void tcp_slow_start(struct tcp_sock *tp) if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh) cnt = sysctl_tcp_max_ssthresh >> 1; /* limited slow start */ else - cnt = tp->snd_cwnd; /* exponential increase */ + cnt = snd_cwnd; /* exponential increase */ /* RFC3465: ABC * We MAY increase by 2 if discovered delayed ack @@ -334,11 +340,11 @@ void tcp_slow_start(struct tcp_sock *tp) tp->bytes_acked = 0; tp->snd_cwnd_cnt += cnt; - while (tp->snd_cwnd_cnt >= tp->snd_cwnd) { - tp->snd_cwnd_cnt -= tp->snd_cwnd; + while (tp->snd_cwnd_cnt >= snd_cwnd) { + tp->snd_cwnd_cnt -= snd_cwnd; delta++; } - tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp); + tp->snd_cwnd = min(snd_cwnd + delta, tp->snd_cwnd_clamp); } EXPORT_SYMBOL_GPL(tcp_slow_start); -- cgit v1.2.3-59-g8ed1b From 2e5f421211ff76c17130b4597bc06df4eeead24f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 3 Feb 2013 09:13:05 +0000 Subject: tcp: frto should not set snd_cwnd to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9dc274151a548 (tcp: fix ABC in tcp_slow_start()) uncovered a bug in FRTO code : tcp_process_frto() is setting snd_cwnd to 0 if the number of in flight packets is 0. As Neal pointed out, if no packet is in flight we lost our chance to disambiguate whether a loss timeout was spurious. We should assume it was a proper loss. Reported-by: Pasi Kärkkäinen Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Cc: Ilpo Järvinen Cc: Yuchung Cheng Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8aca4ee95ff9..680c4224ed96 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3484,7 +3484,8 @@ static bool tcp_process_frto(struct sock *sk, int flag) ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) tp->undo_marker = 0; - if (!before(tp->snd_una, tp->frto_highmark)) { + if (!before(tp->snd_una, tp->frto_highmark) || + !tcp_packets_in_flight(tp)) { tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); return true; } -- cgit v1.2.3-59-g8ed1b From 92df9b217ee2392024483ba5b85a88d92d60f3c1 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Fri, 1 Feb 2013 15:18:49 +0000 Subject: net: Fix inner_network_header assignment in skb-copy. Use correct inner offset to set inner_network_offset. Found by inspection. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a9a2ae3e2213..32443ebc3e89 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -683,7 +683,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->network_header = old->network_header; new->mac_header = old->mac_header; new->inner_transport_header = old->inner_transport_header; - new->inner_network_header = old->inner_transport_header; + new->inner_network_header = old->inner_network_header; skb_dst_copy(new, old); new->rxhash = old->rxhash; new->ooo_okay = old->ooo_okay; -- cgit v1.2.3-59-g8ed1b From 9665d5d62487e8e7b1f546c00e11107155384b9a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 1 Feb 2013 07:21:41 +0000 Subject: packet: fix leakage of tx_ring memory When releasing a packet socket, the routine packet_set_ring() is reused to free rings instead of allocating them. But when calling it for the first time, it fills req->tp_block_nr with the value of rb->pg_vec_len which in the second invocation makes it bail out since req->tp_block_nr is greater zero but req->tp_block_size is zero. This patch solves the problem by passing a zeroed auto-variable to packet_set_ring() upon each invocation from packet_release(). As far as I can tell, this issue exists even since 69e3c75 (net: TX_RING and packet mmap), i.e. the original inclusion of TX ring support into af_packet, but applies only to sockets with both RX and TX ring allocated, which is probably why this was unnoticed all the time. Signed-off-by: Phil Sutter Cc: Johann Baudy Cc: Daniel Borkmann Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/packet/af_packet.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e639645e8fec..c111bd0e083a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2361,13 +2361,15 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); - memset(&req_u, 0, sizeof(req_u)); - - if (po->rx_ring.pg_vec) + if (po->rx_ring.pg_vec) { + memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 0); + } - if (po->tx_ring.pg_vec) + if (po->tx_ring.pg_vec) { + memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 1); + } fanout_release(sk); -- cgit v1.2.3-59-g8ed1b From eda8eebdd153c48a4e2a3a3ac3cd9e2e31f5c6b3 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Jan 2013 19:40:42 +0000 Subject: powerpc/mm: Fix hash computation function The ASM version of hash computation function was truncating the upper bit. Make the ASM version similar to hpt_hash function. Remove masking vsid bits. Without this patch, we observed hang during bootup due to not satisfying page fault request correctly. The fault handler used wrong hash values to update the HPTE. Hence we kept looping with page fault. hash_page(ea=000001003e260008, access=203, trap=300 ip=3fff91787134 dsisr 42000000 The computed value of hash 000000000f22f390 update: avpnv=4003e46054003e00, hash=000000000722f390, f=80000006, psize: 2 ... BenH: The over-masking has been there for ever but only hurts with the new 64T support introduced in 3.7 Reported-by: Mike Qiu Signed-off-by: Aneesh Kumar K.V Tested-by: Mike Qiu Signed-off-by: Benjamin Herrenschmidt CC: [v3.7] --- arch/powerpc/mm/hash_low_64.S | 62 ++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 56585086413a..7443481a315c 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -115,11 +115,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) sldi r29,r5,SID_SHIFT - VPN_SHIFT rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) or r29,r28,r29 - - /* Calculate hash value for primary slot and store it in r28 */ - rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ - rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */ - xor r28,r5,r0 + /* + * Calculate hash value for primary slot and store it in r28 + * r3 = va, r5 = vsid + * r0 = (va >> 12) & ((1ul << (28 - 12)) -1) + */ + rldicl r0,r3,64-12,48 + xor r28,r5,r0 /* hash */ b 4f 3: /* Calc vpn and put it in r29 */ @@ -130,11 +132,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* * calculate hash value for primary slot and * store it in r28 for 1T segment + * r3 = va, r5 = vsid */ - rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ - clrldi r5,r5,40 /* vsid & 0xffffff */ - rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ - xor r28,r28,r5 + sldi r28,r5,25 /* vsid << 25 */ + /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */ + rldicl r0,r3,64-12,36 + xor r28,r28,r5 /* vsid ^ ( vsid << 25) */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ @@ -407,11 +410,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) */ rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) or r29,r28,r29 - - /* Calculate hash value for primary slot and store it in r28 */ - rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ - rldicl r0,r3,64-12,48 /* (ea >> 12) & 0xffff */ - xor r28,r5,r0 + /* + * Calculate hash value for primary slot and store it in r28 + * r3 = va, r5 = vsid + * r0 = (va >> 12) & ((1ul << (28 - 12)) -1) + */ + rldicl r0,r3,64-12,48 + xor r28,r5,r0 /* hash */ b 4f 3: /* Calc vpn and put it in r29 */ @@ -426,11 +431,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* * Calculate hash value for primary slot and * store it in r28 for 1T segment + * r3 = va, r5 = vsid */ - rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ - clrldi r5,r5,40 /* vsid & 0xffffff */ - rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ - xor r28,r28,r5 + sldi r28,r5,25 /* vsid << 25 */ + /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */ + rldicl r0,r3,64-12,36 + xor r28,r28,r5 /* vsid ^ ( vsid << 25) */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ @@ -752,25 +758,27 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) or r29,r28,r29 - /* Calculate hash value for primary slot and store it in r28 */ - rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ - rldicl r0,r3,64-16,52 /* (ea >> 16) & 0xfff */ - xor r28,r5,r0 + /* Calculate hash value for primary slot and store it in r28 + * r3 = va, r5 = vsid + * r0 = (va >> 16) & ((1ul << (28 - 16)) -1) + */ + rldicl r0,r3,64-16,52 + xor r28,r5,r0 /* hash */ b 4f 3: /* Calc vpn and put it in r29 */ sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT) or r29,r28,r29 - /* * calculate hash value for primary slot and * store it in r28 for 1T segment + * r3 = va, r5 = vsid */ - rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ - clrldi r5,r5,40 /* vsid & 0xffffff */ - rldicl r0,r3,64-16,40 /* (ea >> 16) & 0xffffff */ - xor r28,r28,r5 + sldi r28,r5,25 /* vsid << 25 */ + /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */ + rldicl r0,r3,64-16,40 + xor r28,r28,r5 /* vsid ^ ( vsid << 25) */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ -- cgit v1.2.3-59-g8ed1b From f76e39c531304b114e27c3dd3e0036f56cd33df1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 4 Feb 2013 10:13:15 +0100 Subject: x86/intel/cacheinfo: Shut up annoying warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've been getting the following warning when doing randbuilds since forever. Now it finally pissed me off just the perfect amount so that I can fix it. arch/x86/kernel/cpu/intel_cacheinfo.c:489:27: warning: ‘cache_disable_0’ defined but not used [-Wunused-variable] arch/x86/kernel/cpu/intel_cacheinfo.c:491:27: warning: ‘cache_disable_1’ defined but not used [-Wunused-variable] arch/x86/kernel/cpu/intel_cacheinfo.c:524:27: warning: ‘subcaches’ defined but not used [-Wunused-variable] It happens because in randconfigs where CONFIG_SYSFS is not set, the whole sysfs-interface to L3 cache index disabling is remaining unused and gcc correctly warns about it. Make it optional, depending on CONFIG_SYSFS too, as is the case with other sysfs-related machinery in this file. Signed-off-by: Borislav Petkov Cc: Andreas Herrmann Link: http://lkml.kernel.org/r/1359969195-27362-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/intel_cacheinfo.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index fe9edec6698a..84c1309c4c0c 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -298,8 +298,7 @@ struct _cache_attr { unsigned int); }; -#ifdef CONFIG_AMD_NB - +#if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS) /* * L3 cache descriptors */ @@ -524,9 +523,9 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count, static struct _cache_attr subcaches = __ATTR(subcaches, 0644, show_subcaches, store_subcaches); -#else /* CONFIG_AMD_NB */ +#else #define amd_init_l3_cache(x, y) -#endif /* CONFIG_AMD_NB */ +#endif /* CONFIG_AMD_NB && CONFIG_SYSFS */ static int __cpuinit cpuid4_cache_lookup_regs(int index, -- cgit v1.2.3-59-g8ed1b From 848bf15f361c7c22da7998c81d50ed3dffbc827d Mon Sep 17 00:00:00 2001 From: Vijay Subramanian Date: Thu, 31 Jan 2013 08:24:06 +0000 Subject: tcp: Update MIB counters for drops This patch updates LINUX_MIB_LISTENDROPS in tcp_v4_conn_request() and tcp_v4_err(). tcp_v4_conn_request() in particular can drop SYNs for various reasons which are not currently tracked. Signed-off-by: Vijay Subramanian Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 629937d514eb..eadb693eef55 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -496,6 +496,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) * errors returned from accept(). */ inet_csk_reqsk_queue_drop(sk, req, prev); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); goto out; case TCP_SYN_SENT: @@ -1502,7 +1503,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) */ if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); goto drop; } @@ -1669,6 +1669,7 @@ drop_and_release: drop_and_free: reqsk_free(req); drop: + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return 0; } EXPORT_SYMBOL(tcp_v4_conn_request); -- cgit v1.2.3-59-g8ed1b From 5f1e942cb45d06968b0ce94472d97014e0e1fdc9 Mon Sep 17 00:00:00 2001 From: Vijay Subramanian Date: Thu, 31 Jan 2013 08:24:19 +0000 Subject: tcp: ipv6: Update MIB counters for drops This patch updates LINUX_MIB_LISTENDROPS and LINUX_MIB_LISTENOVERFLOWS in tcp_v6_conn_request() and tcp_v6_err(). tcp_v6_conn_request() in particular can drop SYNs for various reasons which are not currently tracked. Signed-off-by: Vijay Subramanian Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 93825dd3a7c0..4f43537197ef 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -423,6 +423,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, } inet_csk_reqsk_queue_drop(sk, req, prev); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); goto out; case TCP_SYN_SENT: @@ -958,8 +959,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop; } - if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) + if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); goto drop; + } req = inet6_reqsk_alloc(&tcp6_request_sock_ops); if (req == NULL) @@ -1108,6 +1111,7 @@ drop_and_release: drop_and_free: reqsk_free(req); drop: + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return 0; /* don't send reset */ } -- cgit v1.2.3-59-g8ed1b From bf414b369f158bb527f9f29174ada815f961b44c Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Thu, 31 Jan 2013 08:36:05 +0000 Subject: net: usbnet: fix tx_dropped statistics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is normal for minidrivers accumulating frames to return NULL from their tx_fixup function. We do not want to count this as a drop, or log any debug messages. A different exit path is therefore chosen for such drivers, skipping the debug message and the tx_dropped increment. The test for accumulating drivers was however completely bogus, making the exit path selection depend on whether the user had enabled tx_err logging or not. This would arbitrarily mess up accounting for both accumulating and non-accumulating minidrivers, and would result in unwanted debug messages for the accumulating drivers. Fix by testing for FLAG_MULTI_PACKET instead, which probably was the intention from the beginning. This usage match the documented behaviour of this flag: Indicates to usbnet, that USB driver accumulates multiple IP packets. Affects statistic (counters) and short packet handling. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 977837725726..5e33606c1366 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1125,13 +1125,11 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, if (info->tx_fixup) { skb = info->tx_fixup (dev, skb, GFP_ATOMIC); if (!skb) { - if (netif_msg_tx_err(dev)) { - netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); - goto drop; - } else { - /* cdc_ncm collected packet; waits for more */ + /* packet collected; minidriver waiting for more */ + if (info->flags & FLAG_MULTI_PACKET) goto not_drop; - } + netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); + goto drop; } } length = skb->len; -- cgit v1.2.3-59-g8ed1b From 07c7be3d87e5cdaf5f94c271c516456364ef286c Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Mon, 4 Feb 2013 15:14:46 +0800 Subject: USB: storage: Define a new macro for USB storage match rules 1. Define a new macro for USB storage match rules: matching with Vendor ID and interface descriptors. Signed-off-by: fangxiaozhi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 12 ++++++++++++ drivers/usb/storage/usual-tables.c | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 31b3e1a61bbd..cf09b6ba71ff 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -120,6 +120,17 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); .useTransport = use_transport, \ } +#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \ + vendor_name, product_name, use_protocol, use_transport, \ + init_function, Flags) \ +{ \ + .vendorName = vendor_name, \ + .productName = product_name, \ + .useProtocol = use_protocol, \ + .useTransport = use_transport, \ + .initFunction = init_function, \ +} + static struct us_unusual_dev us_unusual_dev_list[] = { # include "unusual_devs.h" { } /* Terminating entry */ @@ -131,6 +142,7 @@ static struct us_unusual_dev for_dynamic_ids = #undef UNUSUAL_DEV #undef COMPLIANT_DEV #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF #ifdef CONFIG_LOCKDEP diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index b78a526910fb..5ef8ce74aae4 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c @@ -41,6 +41,20 @@ #define USUAL_DEV(useProto, useTrans) \ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) } +/* Define the device is matched with Vendor ID and interface descriptors */ +#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \ + vendorName, productName, useProtocol, useTransport, \ + initFunction, flags) \ +{ \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ + | USB_DEVICE_ID_MATCH_VENDOR, \ + .idVendor = (id_vendor), \ + .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), \ + .bInterfaceProtocol = (pr), \ + .driver_info = (flags) \ +} + struct usb_device_id usb_storage_usb_ids[] = { # include "unusual_devs.h" { } /* Terminating entry */ @@ -50,6 +64,7 @@ MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids); #undef UNUSUAL_DEV #undef COMPLIANT_DEV #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF /* * The table of devices to ignore -- cgit v1.2.3-59-g8ed1b From 200e0d994d9d1919b28c87f1a5fb99a8e13b8a0f Mon Sep 17 00:00:00 2001 From: fangxiaozhi Date: Mon, 4 Feb 2013 15:16:34 +0800 Subject: USB: storage: optimize to match the Huawei USB storage devices and support new switch command 1. Optimize the match rules with new macro for Huawei USB storage devices, to avoid to load USB storage driver for the modem interface with Huawei devices. 2. Add to support new switch command for new Huawei USB dongles. Signed-off-by: fangxiaozhi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 76 ++++++++- drivers/usb/storage/initializers.h | 4 +- drivers/usb/storage/unusual_devs.h | 329 +------------------------------------ 3 files changed, 78 insertions(+), 331 deletions(-) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 105d900150c1..16b0bf055eeb 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -92,8 +92,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return 0; } -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us) +/* This places the HUAWEI usb dongles in multi-port mode */ +static int usb_stor_huawei_feature_init(struct us_data *us) { int result; @@ -104,3 +104,75 @@ int usb_stor_huawei_e220_init(struct us_data *us) US_DEBUGP("Huawei mode set result is %d\n", result); return 0; } + +/* + * It will send a scsi switch command called rewind' to huawei dongle. + * When the dongle receives this command at the first time, + * it will reboot immediately. After rebooted, it will ignore this command. + * So it is unnecessary to read its response. + */ +static int usb_stor_huawei_scsi_init(struct us_data *us) +{ + int result = 0; + int act_len = 0; + struct bulk_cb_wrap *bcbw = (struct bulk_cb_wrap *) us->iobuf; + char rewind_cmd[] = {0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + bcbw->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcbw->Tag = 0; + bcbw->DataTransferLength = 0; + bcbw->Flags = bcbw->Lun = 0; + bcbw->Length = sizeof(rewind_cmd); + memset(bcbw->CDB, 0, sizeof(bcbw->CDB)); + memcpy(bcbw->CDB, rewind_cmd, sizeof(rewind_cmd)); + + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcbw, + US_BULK_CB_WRAP_LEN, &act_len); + US_DEBUGP("transfer actual length=%d, result=%d\n", act_len, result); + return result; +} + +/* + * It tries to find the supported Huawei USB dongles. + * In Huawei, they assign the following product IDs + * for all of their mobile broadband dongles, + * including the new dongles in the future. + * So if the product ID is not included in this list, + * it means it is not Huawei's mobile broadband dongles. + */ +static int usb_stor_huawei_dongles_pid(struct us_data *us) +{ + struct usb_interface_descriptor *idesc; + int idProduct; + + idesc = &us->pusb_intf->cur_altsetting->desc; + idProduct = us->pusb_dev->descriptor.idProduct; + /* The first port is CDROM, + * means the dongle in the single port mode, + * and a switch command is required to be sent. */ + if (idesc && idesc->bInterfaceNumber == 0) { + if ((idProduct == 0x1001) + || (idProduct == 0x1003) + || (idProduct == 0x1004) + || (idProduct >= 0x1401 && idProduct <= 0x1500) + || (idProduct >= 0x1505 && idProduct <= 0x1600) + || (idProduct >= 0x1c02 && idProduct <= 0x2202)) { + return 1; + } + } + return 0; +} + +int usb_stor_huawei_init(struct us_data *us) +{ + int result = 0; + + if (usb_stor_huawei_dongles_pid(us)) { + if (us->pusb_dev->descriptor.idProduct >= 0x1446) + result = usb_stor_huawei_scsi_init(us); + else + result = usb_stor_huawei_feature_init(us); + } + return result; +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 529327fbb06b..5376d4fc76f0 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -46,5 +46,5 @@ int usb_stor_euscsi_init(struct us_data *us); * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us); +/* This places the HUAWEI usb dongles in multi-port mode */ +int usb_stor_huawei_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d305a5aa3a5d..72923b56bbf6 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1527,335 +1527,10 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, /* Reported by fangxiaozhi * This brings the HUAWEI data card devices into multi-port mode */ -UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000, +UNUSUAL_VENDOR_INTF(0x12d1, 0x08, 0x06, 0x50, "HUAWEI MOBILE", "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1402, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1404, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1407, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1420, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1421, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1422, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1423, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1424, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1425, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1426, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1427, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1428, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1429, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1430, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1431, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1432, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1433, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1434, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1435, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1436, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1437, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1438, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1439, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, + USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_init, 0), /* Reported by Vilius Bilinkevicius Date: Mon, 4 Feb 2013 15:31:22 -0600 Subject: dlm: check the write size from user Return EINVAL from write if the size is larger than allowed. Do this before allocating kernel memory for the bogus size, which could lead to OOM. Reported-by: Sasha Levin Tested-by: Jana Saout Signed-off-by: David Teigland --- fs/dlm/user.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 7ff49852b0cb..911649a47dd5 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -503,11 +503,11 @@ static ssize_t device_write(struct file *file, const char __user *buf, #endif return -EINVAL; -#ifdef CONFIG_COMPAT - if (count > sizeof(struct dlm_write_request32) + DLM_RESNAME_MAXLEN) -#else + /* + * can't compare against COMPAT/dlm_write_request32 because + * we don't yet know if is64bit is zero + */ if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN) -#endif return -EINVAL; kbuf = kzalloc(count + 1, GFP_NOFS); -- cgit v1.2.3-59-g8ed1b From a5ffbe0a1993a27072742ef7db6cf9839956fce9 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 2 Feb 2013 15:55:00 -0600 Subject: rtlwifi: Fix scheduling while atomic bug Kernel commits 41affd5 and 6539306 changed the locking in rtl_lps_leave() from a spinlock to a mutex by doing the calls indirectly from a work queue to reduce the time that interrupts were disabled. This change was fine for most systems; however a scheduling while atomic bug was reported in https://bugzilla.redhat.com/show_bug.cgi?id=903881. The backtrace indicates that routine rtl_is_special(), which calls rtl_lps_leave() in three places was entered in atomic context. These direct calls are replaced by putting a request on the appropriate work queue. Signed-off-by: Larry Finger Reported-and-tested-by: Nathaniel Doherty Cc: Nathaniel Doherty Cc: Stanislaw Gruszka Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 4494d130b37c..0f8b05185eda 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1004,7 +1004,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv-> + works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1014,7 +1015,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } } else if (ETH_P_ARP == ether_type) { if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1024,7 +1025,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } -- cgit v1.2.3-59-g8ed1b From c50ae9470e542862f782e2d9c106270152bbf3ce Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 Feb 2013 23:25:33 +0100 Subject: bcma: unregister gpios before unloading bcma This patch unregisters the gpio chip before bcma gets unloaded. Signed-off-by: Hauke Mehrtens Reported-by: Piotr Haber Signed-off-by: John W. Linville --- drivers/bcma/bcma_private.h | 5 +++++ drivers/bcma/driver_gpio.c | 5 +++++ drivers/bcma/main.c | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 4a2d72ec6d43..966ce4d05791 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -94,11 +94,16 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); #ifdef CONFIG_BCMA_DRIVER_GPIO /* driver_gpio.c */ int bcma_gpio_init(struct bcma_drv_cc *cc); +int bcma_gpio_unregister(struct bcma_drv_cc *cc); #else static inline int bcma_gpio_init(struct bcma_drv_cc *cc) { return -ENOTSUPP; } +static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc) +{ + return 0; +} #endif /* CONFIG_BCMA_DRIVER_GPIO */ #endif diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 9a6f585da2d9..71f755c06fc6 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -96,3 +96,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) return gpiochip_add(chip); } + +int bcma_gpio_unregister(struct bcma_drv_cc *cc) +{ + return gpiochip_remove(&cc->gpio); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 53ba20ca17e0..e08b9c604448 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -268,6 +268,13 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) void bcma_bus_unregister(struct bcma_bus *bus) { struct bcma_device *cores[3]; + int err; + + err = bcma_gpio_unregister(&bus->drv_cc); + if (err == -EBUSY) + bcma_err(bus, "Some GPIOs are still in use.\n"); + else if (err) + bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); -- cgit v1.2.3-59-g8ed1b From 600485edaef65d89f5c44ce62baa7cac961cd50d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 Feb 2013 23:25:34 +0100 Subject: ssb: unregister gpios before unloading ssb This patch unregisters the gpio chip before ssb gets unloaded. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/driver_gpio.c | 12 ++++++++++++ drivers/ssb/main.c | 9 +++++++++ drivers/ssb/ssb_private.h | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index 97ac0a38e3d0..eb2753008ef0 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c @@ -174,3 +174,15 @@ int ssb_gpio_init(struct ssb_bus *bus) return -1; } + +int ssb_gpio_unregister(struct ssb_bus *bus) +{ + if (ssb_chipco_available(&bus->chipco) || + ssb_extif_available(&bus->extif)) { + return gpiochip_remove(&bus->gpio); + } else { + SSB_WARN_ON(1); + } + + return -1; +} diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index c82c5c95fe85..7140c88738f4 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -443,6 +443,15 @@ static void ssb_devices_unregister(struct ssb_bus *bus) void ssb_bus_unregister(struct ssb_bus *bus) { + int err; + + err = ssb_gpio_unregister(bus); + if (err == -EBUSY) + ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n"); + else if (err) + ssb_dprintk(KERN_ERR PFX + "Can not unregister GPIO driver: %i\n", err); + ssb_buses_lock(); ssb_devices_unregister(bus); list_del(&bus->list); diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 6c10b66c796c..da38305a2d22 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -252,11 +252,16 @@ static inline void ssb_extif_init(struct ssb_extif *extif) #ifdef CONFIG_SSB_DRIVER_GPIO extern int ssb_gpio_init(struct ssb_bus *bus); +extern int ssb_gpio_unregister(struct ssb_bus *bus); #else /* CONFIG_SSB_DRIVER_GPIO */ static inline int ssb_gpio_init(struct ssb_bus *bus) { return -ENOTSUPP; } +static inline int ssb_gpio_unregister(struct ssb_bus *bus) +{ + return 0; +} #endif /* CONFIG_SSB_DRIVER_GPIO */ #endif /* LINUX_SSB_PRIVATE_H_ */ -- cgit v1.2.3-59-g8ed1b From 7b2385b95363c9ff49801c19cba2489a05bd6672 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 2 Feb 2013 14:36:50 +0100 Subject: brcmsmac: rework of mac80211 .flush() callback operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch addresses a long standing issue of the driver with the mac80211 .flush() callback. Since implementing the .flush() callback a number of issues have been fixed, but a WARN_ON_ONCE() was still triggered because the timeout on the flush could still occur. This patch changes the awkward design using msleep() into one using a waitqueue. The waiting flush() context will kick the transmit dma when it is idle and the timeout used waiting for the event is set to 500 ms. Worst case there can be 64 frames outstanding for transmit in the driver. At a rate of 1Mbps that would take 1.5 seconds assuming MTU is 1500 bytes and ignoring retries. The WARN_ON_ONCE() is also removed as this was put in to indicate the flush timeout as a reason for the driver to stall. That was not happening since fixing endless AMPDU retries with following upstream commit: commit 85091fc0a75653e239dc8379658515e577544927 Author: Arend van Spriel Date: Thu Feb 23 18:38:22 2012 +0100 brcm80211: smac: fix endless retry of A-MPDU transmissions bugzilla: 42840 bugzilla@redhat: bugzilla@redhat: Cc: Jonathan Nieder Cc: Stanislaw Gruszka Cc: Camaleón Cc: Milan Bouchet-Valat Cc: Seth Forshee Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Piotr Haber Signed-off-by: Arend van Spriel Acked-by: Seth Forshee Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 35 +++++++++++++--------- .../net/wireless/brcm80211/brcmsmac/mac80211_if.h | 3 +- drivers/net/wireless/brcm80211/brcmsmac/main.c | 15 ++-------- drivers/net/wireless/brcm80211/brcmsmac/pub.h | 3 +- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 0f71d1d4339d..e5fd20994bec 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -36,6 +36,7 @@ #include "debug.h" #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ +#define BRCMS_FLUSH_TIMEOUT 500 /* msec */ /* Flags we support */ #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ @@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); } +static bool brcms_tx_flush_completed(struct brcms_info *wl) +{ + bool result; + + spin_lock_bh(&wl->lock); + result = brcms_c_tx_flush_completed(wl->wlc); + spin_unlock_bh(&wl->lock); + return result; +} + static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) { struct brcms_info *wl = hw->priv; + int ret; no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); - /* wait for packet queue and dma fifos to run empty */ - spin_lock_bh(&wl->lock); - brcms_c_wait_for_tx_completion(wl->wlc, drop); - spin_unlock_bh(&wl->lock); + ret = wait_event_timeout(wl->tx_flush_wq, + brcms_tx_flush_completed(wl), + msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT)); + + brcms_dbg_mac80211(wl->wlc->hw->d11core, + "ret=%d\n", jiffies_to_msecs(ret)); } static const struct ieee80211_ops brcms_ops = { @@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data) done: spin_unlock_bh(&wl->lock); + wake_up(&wl->tx_flush_wq); } /* @@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) atomic_set(&wl->callbacks, 0); + init_waitqueue_head(&wl->tx_flush_wq); + /* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); @@ -1609,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl) spin_lock_bh(&wl->lock); return blocked; } - -/* - * precondition: perimeter lock has been acquired - */ -void brcms_msleep(struct brcms_info *wl, uint ms) -{ - spin_unlock_bh(&wl->lock); - msleep(ms); - spin_lock_bh(&wl->lock); -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 9358bd5ebd35..947ccacf43e6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -68,6 +68,8 @@ struct brcms_info { spinlock_t lock; /* per-device perimeter lock */ spinlock_t isr_lock; /* per-device ISR synchronization lock */ + /* tx flush */ + wait_queue_head_t tx_flush_wq; /* timer related fields */ atomic_t callbacks; /* # outstanding callback functions */ @@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, extern void brcms_free_timer(struct brcms_timer *timer); extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); extern bool brcms_del_timer(struct brcms_timer *timer); -extern void brcms_msleep(struct brcms_info *wl, uint ms); extern void brcms_dpc(unsigned long data); extern void brcms_timer(struct brcms_timer *t); extern void brcms_fatal_error(struct brcms_info *wl); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 9f3d7e9f3bb5..8b5839008af3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -7511,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc) return wlc->band->bandunit; } -void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) +bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc) { - int timeout = 20; int i; /* Kick DMA to send any pending AMPDU */ for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) if (wlc->hw->di[i]) - dma_txflush(wlc->hw->di[i]); + dma_kick_tx(wlc->hw->di[i]); - /* wait for queue and DMA fifos to run dry */ - while (brcms_txpktpendtot(wlc) > 0) { - brcms_msleep(wlc->wl, 1); - - if (--timeout == 0) - break; - } - - WARN_ON_ONCE(timeout == 0); + return !brcms_txpktpendtot(wlc); } void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 4fb2834f4e64..b0f14b7b8616 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); extern void brcms_c_scan_start(struct brcms_c_info *wlc); extern void brcms_c_scan_stop(struct brcms_c_info *wlc); extern int brcms_c_get_curband(struct brcms_c_info *wlc); -extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, - bool drop); extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, @@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); +extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); #endif /* _BRCM_PUB_H_ */ -- cgit v1.2.3-59-g8ed1b From a9bae189542e71f91e61a4428adf6e5a7dfe8063 Mon Sep 17 00:00:00 2001 From: Vyacheslav Dubeyko Date: Mon, 4 Feb 2013 14:28:41 -0800 Subject: nilfs2: fix fix very long mount time issue There exists a situation when GC can work in background alone without any other filesystem activity during significant time. The nilfs_clean_segments() method calls nilfs_segctor_construct() that updates superblocks in the case of NILFS_SC_SUPER_ROOT and THE_NILFS_DISCONTINUED flags are set. But when GC is working alone the nilfs_clean_segments() is called with unset THE_NILFS_DISCONTINUED flag. As a result, the update of superblocks doesn't occurred all this time and in the case of SPOR superblocks keep very old values of last super root placement. SYMPTOMS: Trying to mount a NILFS2 volume after SPOR in such environment ends with very long mounting time (it can achieve about several hours in some cases). REPRODUCING PATH: 1. It needs to use external USB HDD, disable automount and doesn't make any additional filesystem activity on the NILFS2 volume. 2. Generate temporary file with size about 100 - 500 GB (for example, dd if=/dev/zero of= bs=1073741824 count=200). The size of file defines duration of GC working. 3. Then it needs to delete file. 4. Start GC manually by means of command "nilfs-clean -p 0". When you start GC by means of such way then, at the end, superblocks is updated by once. So, for simulation of SPOR, it needs to wait sometime (15 - 40 minutes) and simply switch off USB HDD manually. 5. Switch on USB HDD again and try to mount NILFS2 volume. As a result, NILFS2 volume will mount during very long time. REPRODUCIBILITY: 100% FIX: This patch adds checking that superblocks need to update and set THE_NILFS_DISCONTINUED flag before nilfs_clean_segments() call. Reported-by: Sergey Alexandrov Signed-off-by: Vyacheslav Dubeyko Tested-by: Vyacheslav Dubeyko Acked-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index fdb180769485..f3859354e41a 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -664,8 +664,11 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, if (ret < 0) printk(KERN_ERR "NILFS: GC failed during preparation: " "cannot read source blocks: err=%d\n", ret); - else + else { + if (nilfs_sb_need_update(nilfs)) + set_nilfs_discontinued(nilfs); ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); + } nilfs_remove_all_gcinodes(nilfs); clear_nilfs_gc_running(nilfs); -- cgit v1.2.3-59-g8ed1b From 85facf2570698ca6082326df4d63edebc9c9d96e Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 4 Feb 2013 14:28:42 -0800 Subject: thp: avoid dumping huge zero page No reason to preserve the huge zero page in core dumps. Reported-by: Michel Lespinasse Signed-off-by: Kirill A. Shutemov Reviewed-by: Michel Lespinasse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 6001ee6347a9..b5783d81eda9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1257,6 +1257,10 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, if (flags & FOLL_WRITE && !pmd_write(*pmd)) goto out; + /* Avoid dumping huge zero page */ + if ((flags & FOLL_DUMP) && is_huge_zero_pmd(*pmd)) + return ERR_PTR(-EFAULT); + page = pmd_page(*pmd); VM_BUG_ON(!PageHead(page)); if (flags & FOLL_TOUCH) { -- cgit v1.2.3-59-g8ed1b From 1363b563a728097f34af9469452ec656995ca033 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 4 Feb 2013 14:28:43 -0800 Subject: tools/vm: add .gitignore to ignore built binaries There is no .gitignore in tools/vm, so 'git status' always show built binaries. To ignore this, add .gitignore. Signed-off-by: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tools/vm/.gitignore diff --git a/tools/vm/.gitignore b/tools/vm/.gitignore new file mode 100644 index 000000000000..44f095fa2604 --- /dev/null +++ b/tools/vm/.gitignore @@ -0,0 +1,2 @@ +slabinfo +page-types -- cgit v1.2.3-59-g8ed1b From 3bdf8cd3226fe11f26ce32bbb4c5e381cf807c89 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Mon, 4 Feb 2013 14:28:44 -0800 Subject: drivers/rtc/rtc-vt8500.c: fix year field in vt8500_rtc_set_time() The year field is incorrectly masked when setting the date. If the year is beyond 2099, the year field will be incorrectly updated in hardware. This patch masks the year field correctly. Signed-off-by: Edgar Toernig Signed-off-by: Tony Prisk Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-vt8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 00c930f4b6f3..2730533e2d2d 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -137,7 +137,7 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) return -EINVAL; } - writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S) + writel((bin2bcd(tm->tm_year % 100) << DATE_YEAR_S) | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S) | (bin2bcd(tm->tm_mday)) | ((tm->tm_year >= 200) << DATE_CENTURY_S), -- cgit v1.2.3-59-g8ed1b From be7517d6ab9722f0abad6ba5ffd39cfced95549c Mon Sep 17 00:00:00 2001 From: Tony Lu Date: Mon, 4 Feb 2013 14:28:46 -0800 Subject: mm/hugetlb: set PTE as huge in hugetlb_change_protection and remove_migration_pte When setting a huge PTE, besides calling pte_mkhuge(), we also need to call arch_make_huge_pte(), which we indeed do in make_huge_pte(), but we forget to do in hugetlb_change_protection() and remove_migration_pte(). Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf Reviewed-by: Michal Hocko Acked-by: Hillf Danton Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 1 + mm/migrate.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 4f3ea0b1e57c..546db81820e4 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3033,6 +3033,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma, if (!huge_pte_none(huge_ptep_get(ptep))) { pte = huge_ptep_get_and_clear(mm, address, ptep); pte = pte_mkhuge(pte_modify(pte, newprot)); + pte = arch_make_huge_pte(pte, vma, NULL, 0); set_huge_pte_at(mm, address, ptep, pte); pages++; } diff --git a/mm/migrate.c b/mm/migrate.c index c38778610aa8..2fd8b4af4744 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -160,8 +160,10 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma, if (is_write_migration_entry(entry)) pte = pte_mkwrite(pte); #ifdef CONFIG_HUGETLB_PAGE - if (PageHuge(new)) + if (PageHuge(new)) { pte = pte_mkhuge(pte); + pte = arch_make_huge_pte(pte, vma, new, 0); + } #endif flush_cache_page(vma, addr, pte_pfn(pte)); set_pte_at(mm, addr, ptep, pte); -- cgit v1.2.3-59-g8ed1b From 249d9d9d6b7bfa3cf96c17d368eba2e32122aad1 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Mon, 4 Feb 2013 14:28:47 -0800 Subject: MAINTAINERS: update avr32 web ressources Web resource http://avr32linux.org/ is no longer available. We add the mirror of the web page foud at http://mirror.egtvedt.no/avr32linux.org/. Signed-off-by: Matthias Brugger Cc: Hans-Christian Egtvedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 212c255b9347..35a56bcd5e75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1489,7 +1489,7 @@ AVR32 ARCHITECTURE M: Haavard Skinnemoen M: Hans-Christian Egtvedt W: http://www.atmel.com/products/AVR32/ -W: http://avr32linux.org/ +W: http://mirror.egtvedt.no/avr32linux.org/ W: http://avrfreaks.net/ S: Maintained F: arch/avr32/ -- cgit v1.2.3-59-g8ed1b From 631b0cfdbd801ceae8762e8d287f15da26792ebe Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Mon, 4 Feb 2013 14:28:48 -0800 Subject: mm: fix wrong comments about anon_vma lock We use rwsem since commit 5a505085f043 ("mm/rmap: Convert the struct anon_vma::mutex to an rwsem"). And most of comments are converted to the new rwsem lock; while just 2 more missed from: $ git grep 'anon_vma->mutex' Signed-off-by: Yuanhan Liu Acked-by: Ingo Molnar Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmu_notifier.h | 2 +- mm/mmap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index bc823c4c028b..deca87452528 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -151,7 +151,7 @@ struct mmu_notifier_ops { * Therefore notifier chains can only be traversed when either * * 1. mmap_sem is held. - * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->mutex). + * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->rwsem). * 3. No other concurrent thread can access the list (release) */ struct mmu_notifier { diff --git a/mm/mmap.c b/mm/mmap.c index 35730ee9d515..d1e4124f3d0e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2943,7 +2943,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping) * vma in this mm is backed by the same anon_vma or address_space. * * We can take all the locks in random order because the VM code - * taking i_mmap_mutex or anon_vma->mutex outside the mmap_sem never + * taking i_mmap_mutex or anon_vma->rwsem outside the mmap_sem never * takes more than one of them in a row. Secondly we're protected * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex. * -- cgit v1.2.3-59-g8ed1b From 91c777d86752b00bb3a1d8efa3d8f7e1264f38a9 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Mon, 4 Feb 2013 14:28:49 -0800 Subject: memcg: fix typo in kmemcg cache walk macro The macro for_each_memcg_cache_index contains a silly yet potentially deadly mistake. Although the macro parameter is _idx, the loop tests are done over i, not _idx. This hasn't generated any problems so far, because all users use i as a loop index. However, while playing with an extension of the code I ended using another loop index and the compiler was quick to complain. Unfortunately, this is not the kind of thing that testing reveals =( Signed-off-by: Glauber Costa Cc: Kamezawa Hiroyuki Cc: Johannes Weiner Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 0108a56f814e..28bd5fa2ff2e 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -429,7 +429,7 @@ extern int memcg_limited_groups_array_size; * the slab_mutex must be held when looping through those caches */ #define for_each_memcg_cache_index(_idx) \ - for ((_idx) = 0; i < memcg_limited_groups_array_size; (_idx)++) + for ((_idx) = 0; (_idx) < memcg_limited_groups_array_size; (_idx)++) static inline bool memcg_kmem_enabled(void) { -- cgit v1.2.3-59-g8ed1b From 326b1ffc136d944d403a2b44dc3abace2a4e10fd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Feb 2013 14:28:51 -0800 Subject: checkpatch: fix $Float creation of match variables Commit 74349bccedb3 ("checkpatch: add support for floating point constants") added an unnecessary match variable that caused tests that used a $Constant or $LvalOrFunc to have one too many matches. This causes problems with usleep_range, min/max and other extended tests. Avoid using match variables in $Float. Avoid using match variables in $Assignment too. Signed-off-by: Joe Perches Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 4d2c7dfdaabd..2bb08a962ce3 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -230,12 +230,12 @@ our $Inline = qr{inline|__always_inline|noinline}; our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; our $Lval = qr{$Ident(?:$Member)*}; -our $Float_hex = qr{(?i:0x[0-9a-f]+p-?[0-9]+[fl]?)}; -our $Float_dec = qr{(?i:((?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?))}; -our $Float_int = qr{(?i:[0-9]+e-?[0-9]+[fl]?)}; +our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; +our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; +our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; our $Float = qr{$Float_hex|$Float_dec|$Float_int}; -our $Constant = qr{(?:$Float|(?i:(?:0x[0-9a-f]+|[0-9]+)[ul]*))}; -our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; +our $Constant = qr{$Float|(?i)(?:0x[0-9a-f]+|[0-9]+)[ul]*}; +our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; our $Compare = qr{<=|>=|==|!=|<|>}; our $Operators = qr{ <=|>=|==|!=| -- cgit v1.2.3-59-g8ed1b From 275aaa68334c45f616c6576f20201e9890c5da18 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Feb 2013 14:28:52 -0800 Subject: samples/seccomp: be less stupid about cross compiling The seccomp filters are currently built for the build host, not for the machine that they are going to run on, but they are also built for with the -m32 flag if the kernel is built for a 32 bit machine, both of which seems rather odd. It broke allyesconfig on my machine, which is x86-64, but building for 32 bit ARM, with this error message: In file included from /usr/include/stdio.h:28:0, from samples/seccomp/bpf-fancy.c:15: /usr/include/features.h:324:26: fatal error: bits/predefs.h: No such file or directory because there are no 32 bit libc headers installed on this machine. We should really be building all the samples for the target machine rather than the build host, but since the infrastructure for that appears to be missing right now, let's be a little bit smarter and not pass the '-m32' flag to the HOSTCC when cross- compiling. Signed-off-by: Arnd Bergmann Acked-by: Kees Cook Cc: Heiko Carstens Cc: James Morris Acked-by: Will Drewry Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/seccomp/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile index bbbd276659ba..7203e66dcd6f 100644 --- a/samples/seccomp/Makefile +++ b/samples/seccomp/Makefile @@ -19,6 +19,7 @@ bpf-direct-objs := bpf-direct.o # Try to match the kernel target. ifndef CONFIG_64BIT +ifndef CROSS_COMPILE # s390 has -m31 flag to build 31 bit binaries ifndef CONFIG_S390 @@ -35,6 +36,7 @@ HOSTLOADLIBES_bpf-direct += $(MFLAG) HOSTLOADLIBES_bpf-fancy += $(MFLAG) HOSTLOADLIBES_dropper += $(MFLAG) endif +endif # Tell kbuild to always build the programs always := $(hostprogs-y) -- cgit v1.2.3-59-g8ed1b From 72fca4a4b32dc778b5b885c3498700e42b610d49 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Mon, 4 Feb 2013 14:28:53 -0800 Subject: drivers/rtc/rtc-isl1208.c: call rtc_update_irq() from the alarm irq handler Previously the alarm event was not propagated into the RTC subsystem. By adding a call to rtc_update_irq, this fixes a timeout problem with the hwclock utility. Signed-off-by: Jan Luebbe Cc: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-isl1208.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index afb7cfa85ccc..c016ad81767a 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -506,6 +506,7 @@ isl1208_rtc_interrupt(int irq, void *data) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct i2c_client *client = data; + struct rtc_device *rtc = i2c_get_clientdata(client); int handled = 0, sr, err; /* @@ -528,6 +529,8 @@ isl1208_rtc_interrupt(int irq, void *data) if (sr & ISL1208_REG_SR_ALM) { dev_dbg(&client->dev, "alarm!\n"); + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + /* Clear the alarm */ sr &= ~ISL1208_REG_SR_ALM; sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); -- cgit v1.2.3-59-g8ed1b From e7e034e18a0ab6bafb2425c3242cac311164f4d6 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 4 Feb 2013 14:28:54 -0800 Subject: drivers/rtc/rtc-pl031.c: fix the missing operation on enable The RTC control register should be enabled in the process of initializing. Without this patch, I failed to enable RTC in Hisilicon Hi3620 SoC. The register mapping section in RTC is always read as zero. So I doubt that ST guys may already enable this register in bootloader. So they won't meet this issue. Signed-off-by: Haojian Zhuang Cc: Srinidhi Kasagar Cc: Linus Walleij Cc: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pl031.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 08378e3cc21c..10c1a3454e48 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -44,6 +44,7 @@ #define RTC_YMR 0x34 /* Year match register */ #define RTC_YLR 0x38 /* Year data load register */ +#define RTC_CR_EN (1 << 0) /* counter enable bit */ #define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */ #define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */ @@ -320,7 +321,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) struct pl031_local *ldata; struct pl031_vendor_data *vendor = id->data; struct rtc_class_ops *ops = &vendor->ops; - unsigned long time; + unsigned long time, data; ret = amba_request_regions(adev, NULL); if (ret) @@ -345,10 +346,11 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev)); dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev)); + data = readl(ldata->base + RTC_CR); /* Enable the clockwatch on ST Variants */ if (vendor->clockwatch) - writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN, - ldata->base + RTC_CR); + data |= RTC_CR_CWEN; + writel(data | RTC_CR_EN, ldata->base + RTC_CR); /* * On ST PL031 variants, the RTC reset value does not provide correct -- cgit v1.2.3-59-g8ed1b From a1ed26703e5e7db1be21177df22558370dc599e6 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 18 Jan 2013 20:35:06 +0100 Subject: pinctrl: exynos: change PINCTRL_EXYNOS option Since pinctrl-exynos can support exynos4 and exynos5 so changed the option name to PINCTRL_EXYNOS for more clarity. Cc: Thomas Abraham Cc: Linus Walleij Cc: Grant Likely Signed-off-by: Kukjin Kim Signed-off-by: Linus Walleij --- arch/arm/mach-exynos/Kconfig | 2 +- drivers/pinctrl/Kconfig | 4 ++-- drivers/pinctrl/Makefile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index e103c290bc9e..85afb031b676 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -414,7 +414,7 @@ config MACH_EXYNOS4_DT select CPU_EXYNOS4210 select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD select PINCTRL - select PINCTRL_EXYNOS4 + select PINCTRL_EXYNOS select USE_OF help Machine support for Samsung Exynos4 machine with device tree enabled. diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efaecefe3f8c..a5f3c8ca480e 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -184,8 +184,8 @@ config PINCTRL_SAMSUNG select PINMUX select PINCONF -config PINCTRL_EXYNOS4 - bool "Pinctrl driver data for Exynos4 SoC" +config PINCTRL_EXYNOS + bool "Pinctrl driver data for Samsung EXYNOS SoCs" depends on OF && GPIOLIB select PINCTRL_SAMSUNG diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index fc4606f27dc7..6e87e52eab5d 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o -obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o +obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o -- cgit v1.2.3-59-g8ed1b From 228f1ce9b8e9e63c3ffc1b03b64d77277cacb89f Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 4 Feb 2013 17:53:34 +0800 Subject: pinctrl: sirf: replace of_gpio_simple_xlate by sirf specific of_xlate the default of_gpio_simple_xlate() will make us fail while getting gpios bigger than 32 by of_get_named_gpio() or related APIs. this patch adds a specific of_xlate callback for sirf gpio_chip and fix the problem. Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sirf.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 498b2ba905de..d02498b30c6e 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -1246,6 +1246,22 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) return of_iomap(np, 0); } +static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE) + return -EINVAL; + + if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE; +} + static int sirfsoc_pinmux_probe(struct platform_device *pdev) { int ret; @@ -1736,6 +1752,8 @@ static int sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE; bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL); bank->chip.gc.of_node = np; + bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate; + bank->chip.gc.of_gpio_n_cells = 2; bank->chip.regs = regs; bank->id = i; bank->is_marco = is_marco; -- cgit v1.2.3-59-g8ed1b From 7e5a90c25f89128c096dbdb0e5451962438b1e05 Mon Sep 17 00:00:00 2001 From: Shlomo Pongratz Date: Mon, 4 Feb 2013 15:29:10 +0000 Subject: IPoIB: Fix crash due to skb double destruct After commit b13912bbb4a2 ("IPoIB: Call skb_dst_drop() once skb is enqueued for sending"), using connected mode and running multithreaded iperf for long time, ie iperf -c -P 16 -t 3600 results in a crash. After the above-mentioned patch, the driver is calling skb_orphan() and skb_dst_drop() after calling post_send() in ipoib_cm.c::ipoib_cm_send() (also in ipoib_ib.c::ipoib_send()) The problem with this is, as is written in a comment in both routines, "it's entirely possible that the completion handler will run before we execute anything after the post_send()." This leads to running the skb cleanup routines simultaneously in two different contexts. The solution is to always perform the skb_orphan() and skb_dst_drop() before queueing the send work request. If an error occurs, then it will be no different than the regular case where dev_free_skb_any() in the completion path, which is assumed to be after these two routines. Signed-off-by: Shlomo Pongratz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 6 +++--- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 03103d2bd641..67b0c1d23678 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -741,6 +741,9 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->mapping = addr; + skb_orphan(skb); + skb_dst_drop(skb); + rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), addr, skb->len); if (unlikely(rc)) { @@ -752,9 +755,6 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ dev->trans_start = jiffies; ++tx->tx_head; - skb_orphan(skb); - skb_dst_drop(skb); - if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", tx->qp->qp_num); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index a1bca70e20aa..2cfa76f5d99e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -600,6 +600,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, netif_stop_queue(dev); } + skb_orphan(skb); + skb_dst_drop(skb); + rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), address->ah, qpn, tx_req, phead, hlen); if (unlikely(rc)) { @@ -615,9 +618,6 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, address->last_send = priv->tx_head; ++priv->tx_head; - - skb_orphan(skb); - skb_dst_drop(skb); } if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) -- cgit v1.2.3-59-g8ed1b From f97b4b5d46d586782b40c8ced81bf9763c18e7cc Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 10 Jan 2013 15:18:35 +0000 Subject: mlx4_core: Fix advertisement of wrong PF context behaviour Commit 08ff32352d6f ("mlx4: 64-byte CQE/EQE support") introduced a regression where older guest VF drivers failed to load even when 64-byte EQEs/CQEs are disabled, since the PF wrongly advertises the new context behaviour anyway. The failure looks like: mlx4_core 0000:00:07.0: Unknown pf context behaviour mlx4_core 0000:00:07.0: Failed to obtain slave caps mlx4_core: probe of 0000:00:07.0 failed with error -38 Fix this by basing this advertisement on dev->caps.flags, which is the operational capabilities used by the QUERY_FUNC_CAP command wrapper (dev_cap->flags holds the firmware capabilities). Reported-by: Alex Williamson Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/net/ethernet/mellanox/mlx4/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index e1bafffbc3b1..9a84c75e9e3f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -380,7 +380,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) } } - if ((dev_cap->flags & + if ((dev->caps.flags & (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) && mlx4_is_master(dev)) dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE; -- cgit v1.2.3-59-g8ed1b From d359f35430c4ea4dd4e24d809aeaeff1fa54c314 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Thu, 24 Jan 2013 18:59:34 +0000 Subject: IB/qib: Fix for broken sparse warning fix Commit 1fb9fed6d489 ("IB/qib: Fix QP RCU sparse warning") broke QP hash list deletion in qp_remove() badly. This patch restores the former for loop behavior, while still fixing the sparse warnings. Cc: Reviewed-by: Gary Leshner Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_qp.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 4850d03870c2..35275099cafd 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -263,20 +263,15 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp) struct qib_qp __rcu **qpp; qpp = &dev->qp_table[n]; - q = rcu_dereference_protected(*qpp, - lockdep_is_held(&dev->qpt_lock)); - for (; q; qpp = &q->next) { + for (; (q = rcu_dereference_protected(*qpp, + lockdep_is_held(&dev->qpt_lock))) != NULL; + qpp = &q->next) if (q == qp) { atomic_dec(&qp->refcount); *qpp = qp->next; rcu_assign_pointer(qp->next, NULL); - q = rcu_dereference_protected(*qpp, - lockdep_is_held(&dev->qpt_lock)); break; } - q = rcu_dereference_protected(*qpp, - lockdep_is_held(&dev->qpt_lock)); - } } spin_unlock_irqrestore(&dev->qpt_lock, flags); -- cgit v1.2.3-59-g8ed1b From 222c81dc3874b4fe98371be665d0447a36447653 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 28 Jan 2013 09:45:20 -0500 Subject: Btrfs: do not merge logged extents if we've removed them from the tree You can run into this problem where if somebody is fsyncing and writing out the existing extents you will have removed the extent map from the em tree, but it's still valid for the current fsync so we go ahead and write it. The problem is we unconditionally try to merge it back into the em tree, but if we've removed it from the em tree that will cause use after free problems. Fix this to only merge if we are still a part of the tree. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/extent_map.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index ed88f5ee4bea..9759911dd34e 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -289,7 +289,8 @@ out: void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em) { clear_bit(EXTENT_FLAG_LOGGING, &em->flags); - try_merge_map(tree, em); + if (em->in_tree) + try_merge_map(tree, em); } /** -- cgit v1.2.3-59-g8ed1b From 0a3404dcff29a7589e8d6ce8c36f97c5411f85b4 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Mon, 28 Jan 2013 12:34:55 +0000 Subject: Btrfs: fix wrong sync_writers decrement in btrfs_file_aio_write() If the checks at the beginning of btrfs_file_aio_write() fail, we needn't decrease ->sync_writers, because we have not increased it. Fix it. Signed-off-by: Miao Xie Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 841cfe3be0e0..a902faab7161 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1595,9 +1595,10 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, if (err < 0 && num_written > 0) num_written = err; } -out: + if (sync) atomic_dec(&BTRFS_I(inode)->sync_writers); +out: sb_end_write(inode->i_sb); current->backing_dev_info = NULL; return num_written ? num_written : err; -- cgit v1.2.3-59-g8ed1b From 843fcf35733164076a77ad833c72c32da8228ad0 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Mon, 28 Jan 2013 12:36:22 +0000 Subject: Btrfs: fix missing release of the space/qgroup reservation in start_transaction() When we fail to start a transaction, we need to release the reserved free space and qgroup space, fix it. Signed-off-by: Miao Xie Reviewed-by: Jan Schmidt Signed-off-by: Josef Bacik --- fs/btrfs/transaction.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index f15494699f3b..fc03aa60b684 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -333,12 +333,14 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type, &root->fs_info->trans_block_rsv, num_bytes, flush); if (ret) - return ERR_PTR(ret); + goto reserve_fail; } again: h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); - if (!h) - return ERR_PTR(-ENOMEM); + if (!h) { + ret = -ENOMEM; + goto alloc_fail; + } /* * If we are JOIN_NOLOCK we're already committing a transaction and @@ -365,11 +367,7 @@ again: if (ret < 0) { /* We must get the transaction if we are JOIN_NOLOCK. */ BUG_ON(type == TRANS_JOIN_NOLOCK); - - if (type < TRANS_JOIN_NOLOCK) - sb_end_intwrite(root->fs_info->sb); - kmem_cache_free(btrfs_trans_handle_cachep, h); - return ERR_PTR(ret); + goto join_fail; } cur_trans = root->fs_info->running_transaction; @@ -410,6 +408,19 @@ got_it: if (!current->journal_info && type != TRANS_USERSPACE) current->journal_info = h; return h; + +join_fail: + if (type < TRANS_JOIN_NOLOCK) + sb_end_intwrite(root->fs_info->sb); + kmem_cache_free(btrfs_trans_handle_cachep, h); +alloc_fail: + if (num_bytes) + btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, + num_bytes); +reserve_fail: + if (qgroup_reserved) + btrfs_qgroup_free(root, qgroup_reserved); + return ERR_PTR(ret); } struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, -- cgit v1.2.3-59-g8ed1b From 6f1c36055f96e80031c7fdda3fd5be826b8d7782 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Tue, 29 Jan 2013 03:22:10 +0000 Subject: Btrfs: fix race between snapshot deletion and getting inode While running snapshot testscript created by Mitch and David, the race between autodefrag and snapshot deletion can lead to corruption of dead_root list so that we can get crash on btrfs_clean_old_snapshots(). And besides autodefrag, scrub also does the same thing, ie. read root first and get inode. Here is the story(take autodefrag as an example): (1) when we delete a snapshot or subvolume, it will set its root's refs to zero and do a iput() on its own inode, and if this inode happens to be the only active in-meory one in root's inode rbtree, it will add itself to the global dead_roots list for later cleanup. (2) after (1), the autodefrag thread may read another inode for defrag and the inode is just in the deleted snapshot/subvolume, but all of these are without checking if the root is still valid(refs > 0). So the end up result is adding the deleted snapshot/subvolume's root to the global dead_roots list AGAIN. Fortunately, we already have a srcu lock to avoid the race, ie. subvol_srcu. So all we need to do is to take the lock to protect 'read root and get inode', since we synchronize to wait for the rcu grace period before adding something to the global dead_roots list. Reported-by: Mitch Harder Signed-off-by: Liu Bo Signed-off-by: Josef Bacik --- fs/btrfs/file.c | 22 ++++++++++++++++++---- fs/btrfs/scrub.c | 25 ++++++++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a902faab7161..b06d289f998f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -293,15 +293,24 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, struct btrfs_key key; struct btrfs_ioctl_defrag_range_args range; int num_defrag; + int index; + int ret; /* get the inode */ key.objectid = defrag->root; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); key.offset = (u64)-1; + + index = srcu_read_lock(&fs_info->subvol_srcu); + inode_root = btrfs_read_fs_root_no_name(fs_info, &key); if (IS_ERR(inode_root)) { - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - return PTR_ERR(inode_root); + ret = PTR_ERR(inode_root); + goto cleanup; + } + if (btrfs_root_refs(&inode_root->root_item) == 0) { + ret = -ENOENT; + goto cleanup; } key.objectid = defrag->ino; @@ -309,9 +318,10 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, key.offset = 0; inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL); if (IS_ERR(inode)) { - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - return PTR_ERR(inode); + ret = PTR_ERR(inode); + goto cleanup; } + srcu_read_unlock(&fs_info->subvol_srcu, index); /* do a chunk of defrag */ clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags); @@ -346,6 +356,10 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, iput(inode); return 0; +cleanup: + srcu_read_unlock(&fs_info->subvol_srcu, index); + kmem_cache_free(btrfs_inode_defrag_cachep, defrag); + return ret; } /* diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index bdbb94f245c9..67783e03d121 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -580,20 +580,29 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) int corrected = 0; struct btrfs_key key; struct inode *inode = NULL; + struct btrfs_fs_info *fs_info; u64 end = offset + PAGE_SIZE - 1; struct btrfs_root *local_root; + int srcu_index; key.objectid = root; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; - local_root = btrfs_read_fs_root_no_name(fixup->root->fs_info, &key); - if (IS_ERR(local_root)) + + fs_info = fixup->root->fs_info; + srcu_index = srcu_read_lock(&fs_info->subvol_srcu); + + local_root = btrfs_read_fs_root_no_name(fs_info, &key); + if (IS_ERR(local_root)) { + srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); return PTR_ERR(local_root); + } key.type = BTRFS_INODE_ITEM_KEY; key.objectid = inum; key.offset = 0; - inode = btrfs_iget(fixup->root->fs_info->sb, &key, local_root, NULL); + inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); + srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -606,7 +615,6 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) } if (PageUptodate(page)) { - struct btrfs_fs_info *fs_info; if (PageDirty(page)) { /* * we need to write the data to the defect sector. the @@ -3180,18 +3188,25 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) u64 physical_for_dev_replace; u64 len; struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info; + int srcu_index; key.objectid = root; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; + + srcu_index = srcu_read_lock(&fs_info->subvol_srcu); + local_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(local_root)) + if (IS_ERR(local_root)) { + srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); return PTR_ERR(local_root); + } key.type = BTRFS_INODE_ITEM_KEY; key.objectid = inum; key.offset = 0; inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); + srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); if (IS_ERR(inode)) return PTR_ERR(inode); -- cgit v1.2.3-59-g8ed1b From 5d1f40202bad12d4c70a2d40a420b30d23a72b1a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 30 Jan 2013 14:17:31 -0500 Subject: Btrfs: fix missing i_size update If we have an ordered extent before the ordered extent we are currently completing that is after the current disk_i_size we will put our i_size update into that ordered extent so that we do not expose stale data. The problem is that if our disk i_size is updated past the previous ordered extent we won't update the i_size with the pending i_size update. So check the pending i_size update and if its above the current disk i_size we need to go ahead and try to update. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index f10731297040..fc6840b53d9d 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -836,9 +836,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, * if the disk i_size is already at the inode->i_size, or * this ordered extent is inside the disk i_size, we're done */ - if (disk_i_size == i_size || offset <= disk_i_size) { + if (disk_i_size == i_size) + goto out; + + /* + * We still need to update disk_i_size if outstanding_isize is greater + * than disk_i_size. + */ + if (offset <= disk_i_size && + (!ordered || ordered->outstanding_isize <= disk_i_size)) goto out; - } /* * walk backward from this ordered extent to disk_i_size. -- cgit v1.2.3-59-g8ed1b From 59fe4f41976f6331b695ff049296d082cf621823 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 30 Jan 2013 14:31:31 -0500 Subject: Btrfs: fix possible stale data exposure We specifically do not update the disk i_size if there are ordered extents outstanding for any area between the current disk_i_size and our ordered extent so that we do not expose stale data. The problem is the check we have only checks if the ordered extent starts at or after the current disk_i_size, which doesn't take into account an ordered extent that starts before the current disk_i_size and ends past the disk_i_size. Fix this by checking if the extent ends past the disk_i_size. Thanks, Signed-off-by: Josef Bacik --- fs/btrfs/ordered-data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index fc6840b53d9d..e5ed56729607 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -877,7 +877,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, break; if (test->file_offset >= i_size) break; - if (test->file_offset >= disk_i_size) { + if (entry_end(test) > disk_i_size) { /* * we don't update disk_i_size now, so record this * undealt i_size. Or we will not know the real -- cgit v1.2.3-59-g8ed1b From eb6b88d92c6df083dd09a8c471011e3788dfd7c6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sun, 27 Jan 2013 23:26:00 -0700 Subject: Btrfs: fix EDQUOT handling in btrfs_delalloc_reserve_metadata When btrfs_qgroup_reserve returned a failure, we were missing a counter operation for BTRFS_I(inode)->outstanding_extents++, leading to warning messages about outstanding extents and space_info->bytes_may_use != 0. Additionally, the error handling code didn't take into account that we dropped the inode lock which might require more cleanup. Luckily, all the cleanup code we need is already there and can be shared with reserve_metadata_bytes, which is exactly what this patch does. Reported-by: Lev Vainblat Signed-off-by: Jan Schmidt Signed-off-by: Chris Mason --- fs/btrfs/extent-tree.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 85b8454d9608..61da9d0bb805 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4534,7 +4534,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) unsigned nr_extents = 0; int extra_reserve = 0; enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL; - int ret; + int ret = 0; bool delalloc_lock = true; /* If we are a free space inode we need to not flush since we will be in @@ -4579,20 +4579,18 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) csum_bytes = BTRFS_I(inode)->csum_bytes; spin_unlock(&BTRFS_I(inode)->lock); - if (root->fs_info->quota_enabled) { + if (root->fs_info->quota_enabled) ret = btrfs_qgroup_reserve(root, num_bytes + nr_extents * root->leafsize); - if (ret) { - spin_lock(&BTRFS_I(inode)->lock); - calc_csum_metadata_size(inode, num_bytes, 0); - spin_unlock(&BTRFS_I(inode)->lock); - if (delalloc_lock) - mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); - return ret; - } - } - ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush); + /* + * ret != 0 here means the qgroup reservation failed, we go straight to + * the shared error handling then. + */ + if (ret == 0) + ret = reserve_metadata_bytes(root, block_rsv, + to_reserve, flush); + if (ret) { u64 to_free = 0; unsigned dropped; -- cgit v1.2.3-59-g8ed1b From 51ac8893a7a51b196501164e645583bf78138699 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 6 Feb 2013 10:30:38 -0500 Subject: xen-pciback: rate limit error messages from xen_pcibk_enable_msi{,x}() ... as being guest triggerable (e.g. by invoking XEN_PCI_OP_enable_msi{,x} on a device not being MSI/MSI-X capable). This is CVE-2013-0231 / XSA-43. Also make the two messages uniform in both their wording and severity. Signed-off-by: Jan Beulich Acked-by: Ian Campbell Reviewed-by: Konrad Rzeszutek Wilk --- drivers/xen/xen-pciback/pciback_ops.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 97f5d264c31e..37c1f825f513 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -135,7 +135,6 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev, struct pci_dev *dev, struct xen_pci_op *op) { struct xen_pcibk_dev_data *dev_data; - int otherend = pdev->xdev->otherend_id; int status; if (unlikely(verbose_request)) @@ -144,8 +143,9 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev, status = pci_enable_msi(dev); if (status) { - printk(KERN_ERR "error enable msi for guest %x status %x\n", - otherend, status); + pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI for guest %u: err %d\n", + pci_name(dev), pdev->xdev->otherend_id, + status); op->value = 0; return XEN_PCI_ERR_op_failed; } @@ -223,10 +223,10 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, pci_name(dev), i, op->msix_entries[i].vector); } - } else { - printk(KERN_WARNING DRV_NAME ": %s: failed to enable MSI-X: err %d!\n", - pci_name(dev), result); - } + } else + pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI-X for guest %u: err %d!\n", + pci_name(dev), pdev->xdev->otherend_id, + result); kfree(entries); op->value = result; -- cgit v1.2.3-59-g8ed1b From 68ba45ff389295ddccbb976b8881de7c46140e00 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 31 Jan 2013 14:46:56 +0000 Subject: xen: fix error handling path if xen_allocate_irq_dynamic fails It is possible that the call to xen_allocate_irq_dynamic() returns negative number other than -1. Reviewed-by: David Vrabel Signed-off-by: Wei Liu Signed-off-by: Konrad Rzeszutek Wilk --- 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 0be4df39e953..74d77dfa5f63 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -840,7 +840,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) if (irq == -1) { irq = xen_allocate_irq_dynamic(); - if (irq == -1) + if (irq < 0) goto out; irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, @@ -944,7 +944,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) if (irq == -1) { irq = xen_allocate_irq_dynamic(); - if (irq == -1) + if (irq < 0) goto out; irq_set_chip_and_handler_name(irq, &xen_percpu_chip, -- cgit v1.2.3-59-g8ed1b From 1a65e24b0bb7dde48cac4a2bf74d5558f9e32ba7 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 6 Feb 2013 12:06:02 -0500 Subject: Btrfs: move d_instantiate outside the transaction during mksubvol Dave Sterba triggered a lockdep complaint about lock ordering between the sb_internal lock and the cleaner semaphore. btrfs_lookup_dentry() checks for orphans if we're looking up the inode for a subvolume, and subvolume creation is triggering the lookup with a transaction running. This commit moves the d_instantiate after the transaction closes. Signed-off-by: Chris Mason --- fs/btrfs/ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index afbf3ac2079d..a31cd931d36e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -515,7 +515,6 @@ static noinline int create_subvol(struct btrfs_root *root, BUG_ON(ret); - d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); fail: if (async_transid) { *async_transid = trans->transid; @@ -525,6 +524,10 @@ fail: } if (err && !ret) ret = err; + + if (!ret) + d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); + return ret; } -- cgit v1.2.3-59-g8ed1b From 6731d2095bd4aef18027c72ef845ab1087c3ba63 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 4 Feb 2013 02:14:25 +0000 Subject: tcp: fix for zero packets_in_flight was too broad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are transients during normal FRTO procedure during which the packets_in_flight can go to zero between write_queue state updates and firing the resulting segments out. As FRTO processing occurs during that window the check must be more precise to not match "spuriously" :-). More specificly, e.g., when packets_in_flight is zero but FLAG_DATA_ACKED is true the problematic branch that set cwnd into zero would not be taken and new segments might be sent out later. Signed-off-by: Ilpo Järvinen Tested-by: Eric Dumazet Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 680c4224ed96..ad70a962c20e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3484,8 +3484,7 @@ static bool tcp_process_frto(struct sock *sk, int flag) ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED))) tp->undo_marker = 0; - if (!before(tp->snd_una, tp->frto_highmark) || - !tcp_packets_in_flight(tp)) { + if (!before(tp->snd_una, tp->frto_highmark)) { tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); return true; } @@ -3505,6 +3504,11 @@ static bool tcp_process_frto(struct sock *sk, int flag) } } else { if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) { + if (!tcp_packets_in_flight(tp)) { + tcp_enter_frto_loss(sk, 2, flag); + return true; + } + /* Prevent sending of new data. */ tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)); -- cgit v1.2.3-59-g8ed1b From 41ab3e31bd50b42c85ac0aa0469642866aee2a9a Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 6 Feb 2013 03:24:02 +0000 Subject: ipv6/ip6_gre: fix error case handling in ip6gre_tunnel_xmit() ip6gre_tunnel_xmit() is leaking the skb when we hit this error branch, and the -1 return value from this function is bogus. Use the error handling we already have in place in ip6gre_tunnel_xmit() for this error case to fix this. Signed-off-by: Tommi Rantala Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6_gre.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index c727e4712751..131dd097736d 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -960,7 +960,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, int ret; if (!ip6_tnl_xmit_ctl(t)) - return -1; + goto tx_err; switch (skb->protocol) { case htons(ETH_P_IP): -- cgit v1.2.3-59-g8ed1b From 96316c595697ae9a2a90badd6f00035f2f384773 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Wed, 6 Feb 2013 05:21:53 +0000 Subject: net: cdc_ncm: add another Huawei vendor specific device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding a new vendor specific class/subclass/protocol combination for CDC NCM devices based on information from a GPLed out-of-tree driver from Huawei. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 9197b2c72ca3..00d3b2d37828 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1215,6 +1215,9 @@ static const struct usb_device_id cdc_devs[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46), .driver_info = (unsigned long)&wwan_info, }, + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76), + .driver_info = (unsigned long)&wwan_info, + }, /* Infineon(now Intel) HSPA Modem platform */ { USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443, -- cgit v1.2.3-59-g8ed1b From e21b9d031fa184632c373eedc12e3c296e1aa65b Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Wed, 6 Feb 2013 05:22:08 +0000 Subject: net: qmi_wwan: add more Huawei devices, including E320 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding new class/subclass/protocol combinations based on the GPLed out-of-tree Huawei driver. One of these has already appeared on a device labelled as "E320". Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 2ca7f8ea2dca..c8e05e27f38c 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -351,6 +351,10 @@ static const struct usb_device_id products[] = { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57), .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* HUAWEI_INTERFACE_NDIS_CONTROL_QUALCOMM */ + USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69), + .driver_info = (unsigned long)&qmi_wwan_info, + }, /* 2. Combined interface devices matching on class+protocol */ { /* Huawei E367 and possibly others in "Windows mode" */ @@ -361,6 +365,14 @@ static const struct usb_device_id products[] = { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* HUAWEI_NDIS_SINGLE_INTERFACE_VDF */ + USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x37), + .driver_info = (unsigned long)&qmi_wwan_info, + }, + { /* HUAWEI_INTERFACE_NDIS_HW_QUALCOMM */ + USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x67), + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* Pantech UML290, P4200 and more */ USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), .driver_info = (unsigned long)&qmi_wwan_info, -- cgit v1.2.3-59-g8ed1b From aded024a12b32fc1ed9a80639681daae2d07ec25 Mon Sep 17 00:00:00 2001 From: Sjur Brændeland Date: Tue, 22 Jan 2013 09:50:26 +1030 Subject: virtio_console: Don't access uninitialized data. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't access uninitialized work-queue when removing device. The work queue is initialized only if the device multi-queue. So don't call cancel_work unless this is a multi-queue device. This fixes the following panic: Kernel panic - not syncing: BUG! Call Trace: 62031b28: [<6026085d>] panic+0x16b/0x2d3 62031b30: [<6004ef5e>] flush_work+0x0/0x1d7 62031b60: [<602606f2>] panic+0x0/0x2d3 62031b68: [<600333b0>] memcpy+0x0/0x140 62031b80: [<6002d58a>] unblock_signals+0x0/0x84 62031ba0: [<602609c5>] printk+0x0/0xa0 62031bd8: [<60264e51>] __mutex_unlock_slowpath+0x13d/0x148 62031c10: [<6004ef5e>] flush_work+0x0/0x1d7 62031c18: [<60050234>] try_to_grab_pending+0x0/0x17e 62031c38: [<6004e984>] get_work_gcwq+0x71/0x8f 62031c48: [<60050539>] __cancel_work_timer+0x5b/0x115 62031c78: [<628acc85>] unplug_port+0x0/0x191 [virtio_console] 62031c98: [<6005061c>] cancel_work_sync+0x12/0x14 62031ca8: [<628ace96>] virtcons_remove+0x80/0x15c [virtio_console] 62031ce8: [<628191de>] virtio_dev_remove+0x1e/0x7e [virtio] 62031d08: [<601cf242>] __device_release_driver+0x75/0xe4 62031d28: [<601cf2dd>] device_release_driver+0x2c/0x40 62031d48: [<601ce0dd>] driver_unbind+0x7d/0xc6 62031d88: [<601cd5d9>] drv_attr_store+0x27/0x29 62031d98: [<60115f61>] sysfs_write_file+0x100/0x14d 62031df8: [<600b737d>] vfs_write+0xcb/0x184 62031e08: [<600b58b8>] filp_close+0x88/0x94 62031e38: [<600b7686>] sys_write+0x59/0x88 62031e88: [<6001ced1>] handle_syscall+0x5d/0x80 62031ea8: [<60030a74>] userspace+0x405/0x531 62031f08: [<600d32cc>] sys_dup+0x0/0x5e 62031f28: [<601b11d6>] strcpy+0x0/0x18 62031f38: [<600be46c>] do_execve+0x10/0x12 62031f48: [<600184c7>] run_init_process+0x43/0x45 62031fd8: [<60019a91>] new_thread_handler+0xba/0xbc Signed-off-by: Sjur Brændeland Cc: stable@kernel.org Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 684b0d53764f..ee4dbeafb377 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2062,7 +2062,8 @@ static void virtcons_remove(struct virtio_device *vdev) /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ - cancel_work_sync(&portdev->control_work); + if (use_multiport(portdev)) + cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) unplug_port(port); -- cgit v1.2.3-59-g8ed1b From ff7c60c580d9722f820d85c9c58ca55ecc1ee7c4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Jan 2013 15:08:14 +0100 Subject: drm/ttm: fix fence locking in ttm_buffer_object_transfer, 2nd try This fixes up commit e8e89622ed361c46bf90ba4828e685a8b603f7e5 Author: Daniel Vetter Date: Tue Dec 18 22:25:11 2012 +0100 drm/ttm: fix fence locking in ttm_buffer_object_transfer which leaves behind a might_sleep in atomic context, since the fence_lock spinlock is held over a kmalloc(GFP_KERNEL) call. The fix is to revert the above commit and only take the lock where we need it, around the call to ->sync_obj_ref. v2: Fixup things noticed by Maarten Lankhorst: - Brown paper bag locking bug. - No need for kzalloc if we clear the entire thing on the next line. - check for bo->sync_obj (totally unlikely race, but still someone else could have snuck in) and clear fbo->sync_obj if it's cleared already. Reported-by: Dave Airlie Cc: Jerome Glisse Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo_util.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 44420fca7dfa..8be35c809c7b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -429,7 +429,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_driver *driver = bdev->driver; - fbo = kzalloc(sizeof(*fbo), GFP_KERNEL); + fbo = kmalloc(sizeof(*fbo), GFP_KERNEL); if (!fbo) return -ENOMEM; @@ -448,7 +448,12 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, fbo->vm_node = NULL; atomic_set(&fbo->cpu_writers, 0); - fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); + spin_lock(&bdev->fence_lock); + if (bo->sync_obj) + fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); + else + fbo->sync_obj = NULL; + spin_unlock(&bdev->fence_lock); kref_init(&fbo->list_kref); kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; @@ -661,13 +666,11 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, */ set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - - /* ttm_buffer_object_transfer accesses bo->sync_obj */ - ret = ttm_buffer_object_transfer(bo, &ghost_obj); spin_unlock(&bdev->fence_lock); if (tmp_obj) driver->sync_obj_unref(&tmp_obj); + ret = ttm_buffer_object_transfer(bo, &ghost_obj); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 48856286b64e4b66ec62b94e504d0b29c1ade664 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:35 +0000 Subject: xen/netback: shutdown the ring if it contains garbage. A buggy or malicious frontend should not be able to confuse netback. If we spot anything which is not as it should be then shutdown the device and don't try to continue with the ring in a potentially hostile state. Well behaved and non-hostile frontends will not be penalised. As well as making the existing checks for such errors fatal also add a new check that ensures that there isn't an insane number of requests on the ring (i.e. more than would fit in the ring). If the ring contains garbage then previously is was possible to loop over this insane number, getting an error each time and therefore not generating any more pending requests and therefore not exiting the loop in xen_netbk_tx_build_gops for an externded period. Also turn various netdev_dbg calls which no precipitate a fatal error into netdev_err, they are rate limited because the device is shutdown afterwards. This fixes at least one known DoS/softlockup of the backend domain. Signed-off-by: Ian Campbell Reviewed-by: Konrad Rzeszutek Wilk Acked-by: Jan Beulich Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 3 ++ drivers/net/xen-netback/interface.c | 23 ++++++++------ drivers/net/xen-netback/netback.c | 62 +++++++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 94b79c3338c4..9d7f1723dd8f 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -151,6 +151,9 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb); /* Notify xenvif that ring now has space to send an skb to the frontend */ void xenvif_notify_tx_completion(struct xenvif *vif); +/* Prevent the device from generating any further traffic. */ +void xenvif_carrier_off(struct xenvif *vif); + /* Returns number of ring slots required to send an skb to the frontend */ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb); diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index b7d41f8c338a..b8c5193bd420 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -343,17 +343,22 @@ err: return err; } -void xenvif_disconnect(struct xenvif *vif) +void xenvif_carrier_off(struct xenvif *vif) { struct net_device *dev = vif->dev; - if (netif_carrier_ok(dev)) { - rtnl_lock(); - netif_carrier_off(dev); /* discard queued packets */ - if (netif_running(dev)) - xenvif_down(vif); - rtnl_unlock(); - xenvif_put(vif); - } + + rtnl_lock(); + netif_carrier_off(dev); /* discard queued packets */ + if (netif_running(dev)) + xenvif_down(vif); + rtnl_unlock(); + xenvif_put(vif); +} + +void xenvif_disconnect(struct xenvif *vif) +{ + if (netif_carrier_ok(vif->dev)) + xenvif_carrier_off(vif); atomic_dec(&vif->refcnt); wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index f2d6b78d901d..c2e3336b4f98 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -888,6 +888,13 @@ static void netbk_tx_err(struct xenvif *vif, xenvif_put(vif); } +static void netbk_fatal_tx_err(struct xenvif *vif) +{ + netdev_err(vif->dev, "fatal error; disabling device\n"); + xenvif_carrier_off(vif); + xenvif_put(vif); +} + static int netbk_count_requests(struct xenvif *vif, struct xen_netif_tx_request *first, struct xen_netif_tx_request *txp, @@ -901,19 +908,22 @@ static int netbk_count_requests(struct xenvif *vif, do { if (frags >= work_to_do) { - netdev_dbg(vif->dev, "Need more frags\n"); + netdev_err(vif->dev, "Need more frags\n"); + netbk_fatal_tx_err(vif); return -frags; } if (unlikely(frags >= MAX_SKB_FRAGS)) { - netdev_dbg(vif->dev, "Too many frags\n"); + netdev_err(vif->dev, "Too many frags\n"); + netbk_fatal_tx_err(vif); return -frags; } memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags), sizeof(*txp)); if (txp->size > first->size) { - netdev_dbg(vif->dev, "Frags galore\n"); + netdev_err(vif->dev, "Frag is bigger than frame.\n"); + netbk_fatal_tx_err(vif); return -frags; } @@ -921,8 +931,9 @@ static int netbk_count_requests(struct xenvif *vif, frags++; if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { - netdev_dbg(vif->dev, "txp->offset: %x, size: %u\n", + netdev_err(vif->dev, "txp->offset: %x, size: %u\n", txp->offset, txp->size); + netbk_fatal_tx_err(vif); return -frags; } } while ((txp++)->flags & XEN_NETTXF_more_data); @@ -1095,7 +1106,8 @@ static int xen_netbk_get_extras(struct xenvif *vif, do { if (unlikely(work_to_do-- <= 0)) { - netdev_dbg(vif->dev, "Missing extra info\n"); + netdev_err(vif->dev, "Missing extra info\n"); + netbk_fatal_tx_err(vif); return -EBADR; } @@ -1104,8 +1116,9 @@ static int xen_netbk_get_extras(struct xenvif *vif, if (unlikely(!extra.type || extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { vif->tx.req_cons = ++cons; - netdev_dbg(vif->dev, + netdev_err(vif->dev, "Invalid extra type: %d\n", extra.type); + netbk_fatal_tx_err(vif); return -EINVAL; } @@ -1121,13 +1134,15 @@ static int netbk_set_skb_gso(struct xenvif *vif, struct xen_netif_extra_info *gso) { if (!gso->u.gso.size) { - netdev_dbg(vif->dev, "GSO size must not be zero.\n"); + netdev_err(vif->dev, "GSO size must not be zero.\n"); + netbk_fatal_tx_err(vif); return -EINVAL; } /* Currently only TCPv4 S.O. is supported. */ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { - netdev_dbg(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); + netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); + netbk_fatal_tx_err(vif); return -EINVAL; } @@ -1264,9 +1279,25 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) /* Get a netif from the list with work to do. */ vif = poll_net_schedule_list(netbk); + /* This can sometimes happen because the test of + * list_empty(net_schedule_list) at the top of the + * loop is unlocked. Just go back and have another + * look. + */ if (!vif) continue; + if (vif->tx.sring->req_prod - vif->tx.req_cons > + XEN_NETIF_TX_RING_SIZE) { + netdev_err(vif->dev, + "Impossible number of requests. " + "req_prod %d, req_cons %d, size %ld\n", + vif->tx.sring->req_prod, vif->tx.req_cons, + XEN_NETIF_TX_RING_SIZE); + netbk_fatal_tx_err(vif); + continue; + } + RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do); if (!work_to_do) { xenvif_put(vif); @@ -1294,17 +1325,14 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) work_to_do = xen_netbk_get_extras(vif, extras, work_to_do); idx = vif->tx.req_cons; - if (unlikely(work_to_do < 0)) { - netbk_tx_err(vif, &txreq, idx); + if (unlikely(work_to_do < 0)) continue; - } } ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do); - if (unlikely(ret < 0)) { - netbk_tx_err(vif, &txreq, idx - ret); + if (unlikely(ret < 0)) continue; - } + idx += ret; if (unlikely(txreq.size < ETH_HLEN)) { @@ -1316,11 +1344,11 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) /* No crossing a page as the payload mustn't fragment. */ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { - netdev_dbg(vif->dev, + netdev_err(vif->dev, "txreq.offset: %x, size: %u, end: %lu\n", txreq.offset, txreq.size, (txreq.offset&~PAGE_MASK) + txreq.size); - netbk_tx_err(vif, &txreq, idx); + netbk_fatal_tx_err(vif); continue; } @@ -1348,8 +1376,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; if (netbk_set_skb_gso(vif, skb, gso)) { + /* Failure in netbk_set_skb_gso is fatal. */ kfree_skb(skb); - netbk_tx_err(vif, &txreq, idx); continue; } } -- cgit v1.2.3-59-g8ed1b From 7d5145d8eb2b9791533ffe4dc003b129b9696c48 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 6 Feb 2013 23:41:36 +0000 Subject: xen/netback: don't leak pages on failure in xen_netbk_tx_check_gop. Signed-off-by: Matthew Daley Reviewed-by: Konrad Rzeszutek Wilk Acked-by: Ian Campbell Acked-by: Jan Beulich Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c2e3336b4f98..bf692df966a9 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -147,7 +147,8 @@ void xen_netbk_remove_xenvif(struct xenvif *vif) atomic_dec(&netbk->netfront_count); } -static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx); +static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx, + u8 status); static void make_tx_response(struct xenvif *vif, struct xen_netif_tx_request *txp, s8 st); @@ -1007,30 +1008,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, { struct gnttab_copy *gop = *gopp; u16 pending_idx = *((u16 *)skb->data); - struct pending_tx_info *pending_tx_info = netbk->pending_tx_info; - struct xenvif *vif = pending_tx_info[pending_idx].vif; - struct xen_netif_tx_request *txp; struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i, err, start; /* Check status of header. */ err = gop->status; - if (unlikely(err)) { - pending_ring_idx_t index; - index = pending_index(netbk->pending_prod++); - txp = &pending_tx_info[pending_idx].req; - make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - netbk->pending_ring[index] = pending_idx; - xenvif_put(vif); - } + if (unlikely(err)) + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); for (i = start; i < nr_frags; i++) { int j, newerr; - pending_ring_idx_t index; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); @@ -1039,16 +1030,12 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, if (likely(!newerr)) { /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); continue; } /* Error on this fragment: respond to client with an error. */ - txp = &netbk->pending_tx_info[pending_idx].req; - make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - index = pending_index(netbk->pending_prod++); - netbk->pending_ring[index] = pending_idx; - xenvif_put(vif); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); /* Not the first error? Preceding frags already invalidated. */ if (err) @@ -1056,10 +1043,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, /* First error: invalidate header and preceding fragments. */ pending_idx = *((u16 *)skb->data); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } /* Remember the error: invalidate all subsequent fragments. */ @@ -1093,7 +1080,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb) /* Take an extra reference to offset xen_netbk_idx_release */ get_page(netbk->mmap_pages[pending_idx]); - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } } @@ -1476,7 +1463,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk) txp->size -= data_len; } else { /* Schedule a response immediately. */ - xen_netbk_idx_release(netbk, pending_idx); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); } if (txp->flags & XEN_NETTXF_csum_blank) @@ -1528,7 +1515,8 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk) xen_netbk_tx_submit(netbk); } -static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) +static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx, + u8 status) { struct xenvif *vif; struct pending_tx_info *pending_tx_info; @@ -1542,7 +1530,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx) vif = pending_tx_info->vif; - make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY); + make_tx_response(vif, &pending_tx_info->req, status); index = pending_index(netbk->pending_prod++); netbk->pending_ring[index] = pending_idx; -- cgit v1.2.3-59-g8ed1b From 4cc7c1cb7b11b6f3515bd9075527576a1eecc4aa Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:37 +0000 Subject: xen/netback: free already allocated memory on failure in xen_netbk_get_requests Signed-off-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index bf692df966a9..dcb2d4d3c3ea 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -978,7 +978,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk, pending_idx = netbk->pending_ring[index]; page = xen_netbk_alloc_page(netbk, skb, pending_idx); if (!page) - return NULL; + goto err; gop->source.u.ref = txp->gref; gop->source.domid = vif->domid; @@ -1000,6 +1000,17 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk, } return gop; +err: + /* Unwind, freeing all pages and sending error responses. */ + while (i-- > start) { + xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]), + XEN_NETIF_RSP_ERROR); + } + /* The head too, if necessary. */ + if (start) + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR); + + return NULL; } static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, -- cgit v1.2.3-59-g8ed1b From b9149729ebdcfce63f853aa54a404c6a8f6ebbf3 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Feb 2013 23:41:38 +0000 Subject: netback: correct netbk_tx_err to handle wrap around. Signed-off-by: Ian Campbell Acked-by: Jan Beulich Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index dcb2d4d3c3ea..2b9520c46e97 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -880,7 +880,7 @@ static void netbk_tx_err(struct xenvif *vif, do { make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); - if (cons >= end) + if (cons == end) break; txp = RING_GET_REQUEST(&vif->tx, cons++); } while (1); -- cgit v1.2.3-59-g8ed1b From 586c31f3bf04c290dc0a0de7fc91d20aa9a5ee53 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 7 Feb 2013 00:55:37 +0000 Subject: net: sctp: sctp_auth_key_put: use kzfree instead of kfree For sensitive data like keying material, it is common practice to zero out keys before returning the memory back to the allocator. Thus, use kzfree instead of kfree. Signed-off-by: Daniel Borkmann Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 159b9bc5d633..d8420ae614dc 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -71,7 +71,7 @@ void sctp_auth_key_put(struct sctp_auth_bytes *key) return; if (atomic_dec_and_test(&key->refcnt)) { - kfree(key); + kzfree(key); SCTP_DBG_OBJCNT_DEC(keys); } } -- cgit v1.2.3-59-g8ed1b From 87c084a980325d877dc7e388b8f2f26d5d3b4d01 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Feb 2013 14:00:34 +0000 Subject: l2tp: dont play with skb->truesize Andrew Savchenko reported a DNS failure and we diagnosed that some UDP sockets were unable to send more packets because their sk_wmem_alloc was corrupted after a while (tx_queue column in following trace) $ cat /proc/net/udp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops ... 459: 00000000:0270 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 4507 2 ffff88003d612380 0 466: 00000000:0277 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 4802 2 ffff88003d613180 0 470: 076A070A:007B 00000000:0000 07 FFFF4600:00000000 00:00000000 00000000 123 0 5552 2 ffff880039974380 0 470: 010213AC:007B 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 4986 2 ffff88003dbd3180 0 470: 010013AC:007B 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 4985 2 ffff88003dbd2e00 0 470: 00FCA8C0:007B 00000000:0000 07 FFFFFB00:00000000 00:00000000 00000000 0 0 4984 2 ffff88003dbd2a80 0 ... Playing with skb->truesize is tricky, especially when skb is attached to a socket, as we can fool memory charging. Just remove this code, its not worth trying to be ultra precise in xmit path. Reported-by: Andrew Savchenko Tested-by: Andrew Savchenko Signed-off-by: Eric Dumazet Cc: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 6 ------ net/l2tp/l2tp_ppp.c | 6 ------ 2 files changed, 12 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 06389d5ff120..2ac884d0e89b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1168,8 +1168,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len struct udphdr *uh; struct inet_sock *inet; __wsum csum; - int old_headroom; - int new_headroom; int headroom; int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; int udp_len; @@ -1181,16 +1179,12 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len */ headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + hdr_len; - old_headroom = skb_headroom(skb); if (skb_cow_head(skb, headroom)) { kfree_skb(skb); return NET_XMIT_DROP; } - new_headroom = skb_headroom(skb); skb_orphan(skb); - skb->truesize += new_headroom - old_headroom; - /* Setup L2TP header */ session->build_header(session, __skb_push(skb, hdr_len)); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 286366ef8930..716605c241f4 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -388,8 +388,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) struct l2tp_session *session; struct l2tp_tunnel *tunnel; struct pppol2tp_session *ps; - int old_headroom; - int new_headroom; int uhlen, headroom; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) @@ -408,7 +406,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (tunnel == NULL) goto abort_put_sess; - old_headroom = skb_headroom(skb); uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; headroom = NET_SKB_PAD + sizeof(struct iphdr) + /* IP header */ @@ -418,9 +415,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (skb_cow_head(skb, headroom)) goto abort_put_sess_tun; - new_headroom = skb_headroom(skb); - skb->truesize += new_headroom - old_headroom; - /* Setup PPP header */ __skb_push(skb, sizeof(ppph)); skb->data[0] = ppph[0]; -- cgit v1.2.3-59-g8ed1b From 9c79330d930b5774aed8eb323daebecedce2e245 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 16:18:39 +0000 Subject: net: usb: fix regression from FLAG_NOARP code In commit 6509141f9c2ba74df6cc72ec35cd1865276ae3a4 ("usbnet: add new flag FLAG_NOARP for usb net devices"), the newly added flag NOARP was using an already defined value, which broke drivers using flag MULTI_PACKET. Signed-off-by: Lucas Stach Signed-off-by: David S. Miller --- include/linux/usb/usbnet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 0de078d4cdb9..0e5ac93bab10 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -102,7 +102,6 @@ struct driver_info { #define FLAG_LINK_INTR 0x0800 /* updates link (carrier) status */ #define FLAG_POINTTOPOINT 0x1000 /* possibly use "usb%d" names */ -#define FLAG_NOARP 0x2000 /* device can't do ARP */ /* * Indicates to usbnet, that USB driver accumulates multiple IP packets. @@ -110,6 +109,7 @@ struct driver_info { */ #define FLAG_MULTI_PACKET 0x2000 #define FLAG_RX_ASSEMBLE 0x4000 /* rx packets may span >1 frames */ +#define FLAG_NOARP 0x8000 /* device can't do ARP */ /* init device ... can sleep, or cause probe() failure */ int (*bind)(struct usbnet *, struct usb_interface *); -- cgit v1.2.3-59-g8ed1b From 2bb3135166abcd59979cfcdd3696ba840b6b9d45 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Jan 2013 23:49:57 +0000 Subject: ARM: GIC: fix GIC cpumask initialization Punit Agrawal reports: > I was trying to boot 3.8-rc5 on Realview EB 11MPCore using > realview-smp_defconfig as a starting point but the kernel failed to > progress past the log below (config attached). > > Pawel suggested I try reverting 384a290283f - "ARM: gic: use a private > mapping for CPU target interfaces" that you've authored. With this > commit reverted the kernel boots. > > I am not quite sure why the commit breaks 11MPCore but Pawel (cc'd) > might be able to shed light on that. Some early GIC implementations return zero for the first distributor CPU routing register. This means we can't rely on that telling us which CPU interface we're connected to. We know that these platforms implement PPIs for IRQs 29-31 - but we shouldn't assume that these will always be populated. So, instead, scan for a non-zero CPU routing register in the first 32 IRQs and use that as our CPU mask. Reported-by: Punit Agrawal Reviewed-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/common/gic.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 36ae03a3f5d1..87dfa9026c5b 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -351,6 +351,25 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) irq_set_chained_handler(irq, gic_handle_cascade_irq); } +static u8 gic_get_cpumask(struct gic_chip_data *gic) +{ + void __iomem *base = gic_data_dist_base(gic); + u32 mask, i; + + for (i = mask = 0; i < 32; i += 4) { + mask = readl_relaxed(base + GIC_DIST_TARGET + i); + mask |= mask >> 16; + mask |= mask >> 8; + if (mask) + break; + } + + if (!mask) + pr_crit("GIC CPU mask not found - kernel will fail to boot.\n"); + + return mask; +} + static void __init gic_dist_init(struct gic_chip_data *gic) { unsigned int i; @@ -369,7 +388,9 @@ static void __init gic_dist_init(struct gic_chip_data *gic) /* * Set all global interrupts to this CPU only. */ - cpumask = readl_relaxed(base + GIC_DIST_TARGET + 0); + cpumask = gic_get_cpumask(gic); + cpumask |= cpumask << 8; + cpumask |= cpumask << 16; for (i = 32; i < gic_irqs; i += 4) writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); @@ -400,7 +421,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) * Get what the GIC says our CPU mask is. */ BUG_ON(cpu >= NR_GIC_CPU_IF); - cpu_mask = readl_relaxed(dist_base + GIC_DIST_TARGET + 0); + cpu_mask = gic_get_cpumask(gic); gic_cpu_map[cpu] = cpu_mask; /* -- cgit v1.2.3-59-g8ed1b From e210101dbbabee7677f63f15796572404e3d54ce Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Jan 2013 23:54:26 +0000 Subject: ARM: realview: ensure that we have sufficient IRQs available Realview EB with a rev B MPcore tile results in lots of warnings at boot because it can't allocate enough IRQs. Fix this by increasing the number of available IRQs. WARNING: at /home/rmk/git/linux-rmk/arch/arm/common/gic.c:757 gic_init_bases+0x12c/0x2ec() Cannot allocate irq_descs @ IRQ96, assuming pre-allocated Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c) r6:000002f5 r5:c042c62c r4:c044ff40 r3:c045f240 [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x54/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_fmt+0x38/0x40) [] (warn_slowpath_fmt+0x0/0x40) from [] (gic_init_bases+0x12c/0x2ec) [] (gic_init_bases+0x0/0x2ec) from [] (gic_init_irq+0x8c/0xd8) [] (gic_init_irq+0x0/0xd8) from [] (init_IRQ+0x1c/0x24) [] (init_IRQ+0x0/0x24) from [] (start_kernel+0x1a4/0x300) [] (start_kernel+0x0/0x300) from [<70008070>] (0x70008070) ---[ end trace 1b75b31a2719ed1c ]--- ------------[ cut here ]------------ WARNING: at /home/rmk/git/linux-rmk/kernel/irq/irqdomain.c:234 irq_domain_add_legacy+0x80/0x140() Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c) r6:000000ea r5:c0081a38 r4:00000000 r3:c045f240 [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x54/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_null+0x24/0x2c) [] (warn_slowpath_null+0x0/0x2c) from [] (irq_domain_add_legacy+0x80/0x140) [] (irq_domain_add_legacy+0x0/0x140) from [] (gic_init_bases+0x14c/0x2ec) [] (gic_init_bases+0x0/0x2ec) from [] (gic_init_irq+0x8c/0xd8) [] (gic_init_irq+0x0/0xd8) from [] (init_IRQ+0x1c/0x24) [] (init_IRQ+0x0/0x24) from [] (start_kernel+0x1a4/0x300) [] (start_kernel+0x0/0x300) from [<70008070>] (0x70008070) ---[ end trace 1b75b31a2719ed1d ]--- ------------[ cut here ]------------ WARNING: at /home/rmk/git/linux-rmk/arch/arm/common/gic.c:762 gic_init_bases+0x170/0x2ec() Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c) r6:000002fa r5:c042c670 r4:00000000 r3:c045f240 [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x54/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_null+0x24/0x2c) [] (warn_slowpath_null+0x0/0x2c) from [] (gic_init_bases+0x170/0x2ec) [] (gic_init_bases+0x0/0x2ec) from [] (gic_init_irq+0x8c/0xd8) [] (gic_init_irq+0x0/0xd8) from [] (init_IRQ+0x1c/0x24) [] (init_IRQ+0x0/0x24) from [] (start_kernel+0x1a4/0x300) [] (start_kernel+0x0/0x300) from [<70008070>] (0x70008070) ---[ end trace 1b75b31a2719ed1e ]--- Signed-off-by: Russell King --- arch/arm/mach-realview/include/mach/irqs-eb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/include/mach/irqs-eb.h index d6b5073692d2..44754230fdcc 100644 --- a/arch/arm/mach-realview/include/mach/irqs-eb.h +++ b/arch/arm/mach-realview/include/mach/irqs-eb.h @@ -115,7 +115,7 @@ /* * Only define NR_IRQS if less than NR_IRQS_EB */ -#define NR_IRQS_EB (IRQ_EB_GIC_START + 96) +#define NR_IRQS_EB (IRQ_EB_GIC_START + 128) #if defined(CONFIG_MACH_REALVIEW_EB) \ && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB)) -- cgit v1.2.3-59-g8ed1b From 633dc92a28fc3fea6f08ef34de0b353ff5f9bf08 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Jan 2013 23:55:35 +0000 Subject: ARM: DMA mapping: fix bad atomic test Realview fails to boot with this warning: BUG: spinlock lockup suspected on CPU#0, init/1 lock: 0xcf8bde10, .magic: dead4ead, .owner: init/1, .owner_cpu: 0 Backtrace: [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c) r6:cf8bde10 r5:cf83d1c0 r4:cf8bde10 r3:cf83d1c0 [] (dump_stack+0x0/0x1c) from [] (spin_dump+0x84/0x98) [] (spin_dump+0x0/0x98) from [] (do_raw_spin_lock+0x100/0x198) [] (do_raw_spin_lock+0x0/0x198) from [] (_raw_spin_lock+0x3c/0x44) [] (_raw_spin_lock+0x0/0x44) from [] (pl011_console_write+0xe8/0x11c) [] (pl011_console_write+0x0/0x11c) from [] (call_console_drivers.clone.7+0xdc/0x104) [] (call_console_drivers.clone.7+0x0/0x104) from [] (console_unlock+0x2e8/0x454) [] (console_unlock+0x0/0x454) from [] (vprintk_emit+0x2d8/0x594) [] (vprintk_emit+0x0/0x594) from [] (printk+0x3c/0x44) [] (printk+0x0/0x44) from [] (warn_slowpath_common+0x28/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_null+0x24/0x2c) [] (warn_slowpath_null+0x0/0x2c) from [] (lockdep_trace_alloc+0xd8/0xf0) [] (lockdep_trace_alloc+0x0/0xf0) from [] (kmem_cache_alloc+0x24/0x11c) [] (kmem_cache_alloc+0x0/0x11c) from [] (__get_vm_area_node.clone.24+0x7c/0x16c) [] (__get_vm_area_node.clone.24+0x0/0x16c) from [] (get_vm_area_caller+0x48/0x54) [] (get_vm_area_caller+0x0/0x54) from [] (__alloc_remap_buffer.clone.15+0x38/0xb8) [] (__alloc_remap_buffer.clone.15+0x0/0xb8) from [] (__dma_alloc+0x160/0x2c8) [] (__dma_alloc+0x0/0x2c8) from [] (arm_dma_alloc+0x88/0xa0)[] (arm_dma_alloc+0x0/0xa0) from [] (dma_pool_alloc+0xcc/0x1a8) [] (dma_pool_alloc+0x0/0x1a8) from [] (pl08x_fill_llis_for_desc+0x28/0x568) [] (pl08x_fill_llis_for_desc+0x0/0x568) from [] (pl08x_prep_slave_sg+0x258/0x3b0) [] (pl08x_prep_slave_sg+0x0/0x3b0) from [] (pl011_dma_tx_refill+0x140/0x288) [] (pl011_dma_tx_refill+0x0/0x288) from [] (pl011_start_tx+0xe4/0x120) [] (pl011_start_tx+0x0/0x120) from [] (__uart_start+0x48/0x4c) [] (__uart_start+0x0/0x4c) from [] (uart_start+0x2c/0x3c) [] (uart_start+0x0/0x3c) from [] (uart_write+0xcc/0xf4) [] (uart_write+0x0/0xf4) from [] (n_tty_write+0x1c0/0x3e4) [] (n_tty_write+0x0/0x3e4) from [] (tty_write+0x144/0x240) [] (tty_write+0x0/0x240) from [] (redirected_tty_write+0x98/0xac) [] (redirected_tty_write+0x0/0xac) from [] (vfs_write+0xbc/0x150) [] (vfs_write+0x0/0x150) from [] (sys_write+0x4c/0x78) [] (sys_write+0x0/0x78) from [] (ret_fast_syscall+0x0/0x3c) This happens because the DMA allocation code is not respecting atomic allocations correctly. GFP flags should not be tested for GFP_ATOMIC to determine if an atomic allocation is being requested. GFP_ATOMIC is not a flag but a value. The GFP bitmask flags are all prefixed with __GFP_. The rest of the kernel tests for __GFP_WAIT not being set to indicate an atomic allocation. We need to do the same. Signed-off-by: Russell King --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 076c26d43864..dda3904dc64c 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -640,7 +640,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, if (is_coherent || nommu()) addr = __alloc_simple_buffer(dev, size, gfp, &page); - else if (gfp & GFP_ATOMIC) + else if (!(gfp & __GFP_WAIT)) addr = __alloc_from_pool(size, &page); else if (!IS_ENABLED(CONFIG_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); -- cgit v1.2.3-59-g8ed1b From 79d1f5c9acf9fc8d06e5537083b19114ce87159f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 8 Feb 2013 12:52:29 +0100 Subject: ARM: 7641/1: memory: fix broken mmap by ensuring TASK_UNMAPPED_BASE is aligned We have received multiple reports of mmap failures when running with a 2:2 vm split. These manifest as either -EINVAL with a non page-aligned address (ending 0xaaa) or a SEGV, depending on the application. The issue is commonly observed in children of make, which appears to use bottom-up mmap (assumedly because it changes the stack rlimit). Further investigation reveals that this regression was triggered by 394ef6403abc ("mm: use vm_unmapped_area() on arm architecture"), whereby TASK_UNMAPPED_BASE is no longer page-aligned for bottom-up mmap, causing get_unmapped_area to choke on misaligned addressed. This patch fixes the problem by defining TASK_UNMAPPED_BASE in terms of TASK_SIZE and explicitly aligns the result to 16M, matching the other end of the heap. Acked-by: Nicolas Pitre Reported-by: Steve Capper Reported-by: Jean-Francois Moine Reported-by: Christoffer Dall Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 73cf03aa981e..1c4df27f9332 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -37,7 +37,7 @@ */ #define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) #define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000)) -#define TASK_UNMAPPED_BASE (UL(CONFIG_PAGE_OFFSET) / 3) +#define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M) /* * The maximum size of a 26-bit user space task. -- cgit v1.2.3-59-g8ed1b From ab54ee80aa7585f9666ff4dd665441d7ce41f1e8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 8 Feb 2013 00:19:11 +0000 Subject: atm/iphase: rename fregt_t -> ffreg_t We have conflicting type qualifiers for "freg_t" in s390's ptrace.h and the iphase atm device driver, which causes the compile error below. Unfortunately the s390 typedef can't be renamed, since it's a user visible api, nor can I change the include order in s390 code to avoid the conflict. So simply rename the iphase typedef to a new name. Fixes this compile error: In file included from drivers/atm/iphase.c:66:0: drivers/atm/iphase.h:639:25: error: conflicting type qualifiers for 'freg_t' In file included from next/arch/s390/include/asm/ptrace.h:9:0, from next/arch/s390/include/asm/lowcore.h:12, from next/arch/s390/include/asm/thread_info.h:30, from include/linux/thread_info.h:54, from include/linux/preempt.h:9, from include/linux/spinlock.h:50, from include/linux/seqlock.h:29, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/atm/iphase.c:43: next/arch/s390/include/uapi/asm/ptrace.h:197:3: note: previous declaration of 'freg_t' was here Signed-off-by: Heiko Carstens Acked-by: chas williams - CONTRACTOR Signed-off-by: David S. Miller --- drivers/atm/iphase.h | 146 +++++++++++++++++++++++++-------------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h index 6a0955e6d4fc..53ecac5a2161 100644 --- a/drivers/atm/iphase.h +++ b/drivers/atm/iphase.h @@ -636,82 +636,82 @@ struct rx_buf_desc { #define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE #define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE -typedef volatile u_int freg_t; +typedef volatile u_int ffreg_t; typedef u_int rreg_t; typedef struct _ffredn_t { - freg_t idlehead_high; /* Idle cell header (high) */ - freg_t idlehead_low; /* Idle cell header (low) */ - freg_t maxrate; /* Maximum rate */ - freg_t stparms; /* Traffic Management Parameters */ - freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ - freg_t rm_type; /* */ - u_int filler5[0x17 - 0x06]; - freg_t cmd_reg; /* Command register */ - u_int filler18[0x20 - 0x18]; - freg_t cbr_base; /* CBR Pointer Base */ - freg_t vbr_base; /* VBR Pointer Base */ - freg_t abr_base; /* ABR Pointer Base */ - freg_t ubr_base; /* UBR Pointer Base */ - u_int filler24; - freg_t vbrwq_base; /* VBR Wait Queue Base */ - freg_t abrwq_base; /* ABR Wait Queue Base */ - freg_t ubrwq_base; /* UBR Wait Queue Base */ - freg_t vct_base; /* Main VC Table Base */ - freg_t vcte_base; /* Extended Main VC Table Base */ - u_int filler2a[0x2C - 0x2A]; - freg_t cbr_tab_beg; /* CBR Table Begin */ - freg_t cbr_tab_end; /* CBR Table End */ - freg_t cbr_pointer; /* CBR Pointer */ - u_int filler2f[0x30 - 0x2F]; - freg_t prq_st_adr; /* Packet Ready Queue Start Address */ - freg_t prq_ed_adr; /* Packet Ready Queue End Address */ - freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ - freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ - freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ - freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ - freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ - freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ - u_int filler38[0x40 - 0x38]; - freg_t queue_base; /* Base address for PRQ and TCQ */ - freg_t desc_base; /* Base address of descriptor table */ - u_int filler42[0x45 - 0x42]; - freg_t mode_reg_0; /* Mode register 0 */ - freg_t mode_reg_1; /* Mode register 1 */ - freg_t intr_status_reg;/* Interrupt Status register */ - freg_t mask_reg; /* Mask Register */ - freg_t cell_ctr_high1; /* Total cell transfer count (high) */ - freg_t cell_ctr_lo1; /* Total cell transfer count (low) */ - freg_t state_reg; /* Status register */ - u_int filler4c[0x58 - 0x4c]; - freg_t curr_desc_num; /* Contains the current descriptor num */ - freg_t next_desc; /* Next descriptor */ - freg_t next_vc; /* Next VC */ - u_int filler5b[0x5d - 0x5b]; - freg_t present_slot_cnt;/* Present slot count */ - u_int filler5e[0x6a - 0x5e]; - freg_t new_desc_num; /* New descriptor number */ - freg_t new_vc; /* New VC */ - freg_t sched_tbl_ptr; /* Schedule table pointer */ - freg_t vbrwq_wptr; /* VBR wait queue write pointer */ - freg_t vbrwq_rptr; /* VBR wait queue read pointer */ - freg_t abrwq_wptr; /* ABR wait queue write pointer */ - freg_t abrwq_rptr; /* ABR wait queue read pointer */ - freg_t ubrwq_wptr; /* UBR wait queue write pointer */ - freg_t ubrwq_rptr; /* UBR wait queue read pointer */ - freg_t cbr_vc; /* CBR VC */ - freg_t vbr_sb_vc; /* VBR SB VC */ - freg_t abr_sb_vc; /* ABR SB VC */ - freg_t ubr_sb_vc; /* UBR SB VC */ - freg_t vbr_next_link; /* VBR next link */ - freg_t abr_next_link; /* ABR next link */ - freg_t ubr_next_link; /* UBR next link */ - u_int filler7a[0x7c-0x7a]; - freg_t out_rate_head; /* Out of rate head */ - u_int filler7d[0xca-0x7d]; /* pad out to full address space */ - freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ - freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ - u_int fillercc[0x100-0xcc]; /* pad out to full address space */ + ffreg_t idlehead_high; /* Idle cell header (high) */ + ffreg_t idlehead_low; /* Idle cell header (low) */ + ffreg_t maxrate; /* Maximum rate */ + ffreg_t stparms; /* Traffic Management Parameters */ + ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ + ffreg_t rm_type; /* */ + u_int filler5[0x17 - 0x06]; + ffreg_t cmd_reg; /* Command register */ + u_int filler18[0x20 - 0x18]; + ffreg_t cbr_base; /* CBR Pointer Base */ + ffreg_t vbr_base; /* VBR Pointer Base */ + ffreg_t abr_base; /* ABR Pointer Base */ + ffreg_t ubr_base; /* UBR Pointer Base */ + u_int filler24; + ffreg_t vbrwq_base; /* VBR Wait Queue Base */ + ffreg_t abrwq_base; /* ABR Wait Queue Base */ + ffreg_t ubrwq_base; /* UBR Wait Queue Base */ + ffreg_t vct_base; /* Main VC Table Base */ + ffreg_t vcte_base; /* Extended Main VC Table Base */ + u_int filler2a[0x2C - 0x2A]; + ffreg_t cbr_tab_beg; /* CBR Table Begin */ + ffreg_t cbr_tab_end; /* CBR Table End */ + ffreg_t cbr_pointer; /* CBR Pointer */ + u_int filler2f[0x30 - 0x2F]; + ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */ + ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */ + ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ + ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ + ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ + ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ + ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ + ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ + u_int filler38[0x40 - 0x38]; + ffreg_t queue_base; /* Base address for PRQ and TCQ */ + ffreg_t desc_base; /* Base address of descriptor table */ + u_int filler42[0x45 - 0x42]; + ffreg_t mode_reg_0; /* Mode register 0 */ + ffreg_t mode_reg_1; /* Mode register 1 */ + ffreg_t intr_status_reg;/* Interrupt Status register */ + ffreg_t mask_reg; /* Mask Register */ + ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */ + ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */ + ffreg_t state_reg; /* Status register */ + u_int filler4c[0x58 - 0x4c]; + ffreg_t curr_desc_num; /* Contains the current descriptor num */ + ffreg_t next_desc; /* Next descriptor */ + ffreg_t next_vc; /* Next VC */ + u_int filler5b[0x5d - 0x5b]; + ffreg_t present_slot_cnt;/* Present slot count */ + u_int filler5e[0x6a - 0x5e]; + ffreg_t new_desc_num; /* New descriptor number */ + ffreg_t new_vc; /* New VC */ + ffreg_t sched_tbl_ptr; /* Schedule table pointer */ + ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */ + ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */ + ffreg_t abrwq_wptr; /* ABR wait queue write pointer */ + ffreg_t abrwq_rptr; /* ABR wait queue read pointer */ + ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */ + ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */ + ffreg_t cbr_vc; /* CBR VC */ + ffreg_t vbr_sb_vc; /* VBR SB VC */ + ffreg_t abr_sb_vc; /* ABR SB VC */ + ffreg_t ubr_sb_vc; /* UBR SB VC */ + ffreg_t vbr_next_link; /* VBR next link */ + ffreg_t abr_next_link; /* ABR next link */ + ffreg_t ubr_next_link; /* UBR next link */ + u_int filler7a[0x7c-0x7a]; + ffreg_t out_rate_head; /* Out of rate head */ + u_int filler7d[0xca-0x7d]; /* pad out to full address space */ + ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ + ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ + u_int fillercc[0x100-0xcc]; /* pad out to full address space */ } ffredn_t; typedef struct _rfredn_t { -- cgit v1.2.3-59-g8ed1b From 6ba542a291a5e558603ac51cda9bded347ce7627 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 8 Feb 2013 03:04:34 +0000 Subject: net: sctp: sctp_setsockopt_auth_key: use kzfree instead of kfree In sctp_setsockopt_auth_key, we create a temporary copy of the user passed shared auth key for the endpoint or association and after internal setup, we free it right away. Since it's sensitive data, we should zero out the key before returning the memory back to the allocator. Thus, use kzfree instead of kfree, just as we do in sctp_auth_key_put(). Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9e65758cb038..cedd9bf67b8c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3390,7 +3390,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk, ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey); out: - kfree(authkey); + kzfree(authkey); return ret; } -- cgit v1.2.3-59-g8ed1b From b5c37fe6e24eec194bb29d22fdd55d73bcc709bf Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 8 Feb 2013 03:04:35 +0000 Subject: net: sctp: sctp_endpoint_free: zero out secret key data On sctp_endpoint_destroy, previously used sensitive keying material should be zeroed out before the memory is returned, as we already do with e.g. auth keys when released. Signed-off-by: Daniel Borkmann Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/endpointola.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 17a001bac2cc..1a9c5fb77310 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -249,6 +249,8 @@ void sctp_endpoint_free(struct sctp_endpoint *ep) /* Final destructor for endpoint. */ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) { + int i; + SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); /* Free up the HMAC transform. */ @@ -271,6 +273,9 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); + for (i = 0; i < SCTP_HOW_MANY_SECRETS; ++i) + memset(&ep->secret_key[i], 0, SCTP_SECRET_SIZE); + /* Remove and free the port */ if (sctp_sk(ep->base.sk)->bind_hash) sctp_put_port(ep->base.sk); -- cgit v1.2.3-59-g8ed1b From 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 9 Feb 2013 08:20:39 +1100 Subject: Linux 3.8-rc7 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 54dfde5e9f9e..08ef9bdb80c7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 8 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Unicycling Gorilla # *DOCUMENTATION* -- cgit v1.2.3-59-g8ed1b From bb76563214ec371a461ca5038904a5b93dbd6b46 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 26 Dec 2012 08:29:17 +0000 Subject: MIPS: bcm47xx: separate functions finding flash window addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also check if parallel flash is present at all before accessing it and add support for serial flash on BCMA bus. Signed-off-by: Rafał Miłecki Acked-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4738/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 87 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 48a4c70b3842..64613678ce84 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -23,39 +23,13 @@ static char nvram_buf[NVRAM_SPACE]; -/* Probe for NVRAM header */ -static void early_nvram_init(void) +static void nvram_find_and_copy(u32 base, u32 lim) { -#ifdef CONFIG_BCM47XX_SSB - struct ssb_mipscore *mcore_ssb; -#endif -#ifdef CONFIG_BCM47XX_BCMA - struct bcma_drv_cc *bcma_cc; -#endif struct nvram_header *header; int i; - u32 base = 0; - u32 lim = 0; u32 off; u32 *src, *dst; - switch (bcm47xx_bus_type) { -#ifdef CONFIG_BCM47XX_SSB - case BCM47XX_BUS_TYPE_SSB: - mcore_ssb = &bcm47xx_bus.ssb.mipscore; - base = mcore_ssb->pflash.window; - lim = mcore_ssb->pflash.window_size; - break; -#endif -#ifdef CONFIG_BCM47XX_BCMA - case BCM47XX_BUS_TYPE_BCMA: - bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc; - base = bcma_cc->pflash.window; - lim = bcma_cc->pflash.window_size; - break; -#endif - } - off = FLASH_MIN; while (off <= lim) { /* Windowed flash access */ @@ -86,6 +60,65 @@ found: *dst++ = le32_to_cpu(*src++); } +#ifdef CONFIG_BCM47XX_SSB +static void nvram_init_ssb(void) +{ + struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; + u32 base; + u32 lim; + + if (mcore->pflash.present) { + base = mcore->pflash.window; + lim = mcore->pflash.window_size; + } else { + pr_err("Couldn't find supported flash memory\n"); + return; + } + + nvram_find_and_copy(base, lim); +} +#endif + +#ifdef CONFIG_BCM47XX_BCMA +static void nvram_init_bcma(void) +{ + struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc; + u32 base; + u32 lim; + + if (cc->pflash.present) { + base = cc->pflash.window; + lim = cc->pflash.window_size; +#ifdef CONFIG_BCMA_SFLASH + } else if (cc->sflash.present) { + base = cc->sflash.window; + lim = cc->sflash.size; +#endif + } else { + pr_err("Couldn't find supported flash memory\n"); + return; + } + + nvram_find_and_copy(base, lim); +} +#endif + +static void early_nvram_init(void) +{ + switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: + nvram_init_ssb(); + break; +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + nvram_init_bcma(); + break; +#endif + } +} + int nvram_getenv(char *name, char *val, size_t val_len) { char *var, *value, *end, *eq; -- cgit v1.2.3-59-g8ed1b From ee7e2f3c235f43d815c0be285101b5b91a3bcaa5 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:09 +0000 Subject: MIPS: BCM47XX: use common error codes in nvram reads Instead of using our own error codes use some common codes. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4739/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 4 ++-- arch/mips/bcm47xx/sprom.c | 2 +- arch/mips/include/asm/mach-bcm47xx/nvram.h | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 64613678ce84..e19fc2600b76 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -124,7 +124,7 @@ int nvram_getenv(char *name, char *val, size_t val_len) char *var, *value, *end, *eq; if (!name) - return NVRAM_ERR_INV_PARAM; + return -EINVAL; if (!nvram_buf[0]) early_nvram_init(); @@ -143,6 +143,6 @@ int nvram_getenv(char *name, char *val, size_t val_len) return snprintf(val, val_len, "%s", value); } } - return NVRAM_ERR_ENVNOTFOUND; + return -ENOENT; } EXPORT_SYMBOL(nvram_getenv); diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 289cc0a38638..66b71c363300 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -51,7 +51,7 @@ static int get_nvram_var(const char *prefix, const char *postfix, create_key(prefix, postfix, name, key, sizeof(key)); err = nvram_getenv(key, buf, len); - if (fallback && err == NVRAM_ERR_ENVNOTFOUND && prefix) { + if (fallback && err == -ENOENT && prefix) { create_key(NULL, postfix, name, key, sizeof(key)); err = nvram_getenv(key, buf, len); } diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index 69ef3efe06e7..550a7fc932c9 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -32,9 +32,6 @@ struct nvram_header { #define NVRAM_MAX_VALUE_LEN 255 #define NVRAM_MAX_PARAM_LEN 64 -#define NVRAM_ERR_INV_PARAM -8 -#define NVRAM_ERR_ENVNOTFOUND -9 - extern int nvram_getenv(char *name, char *val, size_t val_len); static inline void nvram_parse_macaddr(char *buf, u8 macaddr[6]) -- cgit v1.2.3-59-g8ed1b From cc4403e02541af226ae6b7da0917c8959dd73a75 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:10 +0000 Subject: MIPS: BCM47XX: return error when init of nvram failed This makes it possible to handle the case of not being able to read the nvram ram. This could happen when the code searching for the specific flash chip have not run jet. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4740/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index e19fc2600b76..80e352e0c995 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -23,7 +23,7 @@ static char nvram_buf[NVRAM_SPACE]; -static void nvram_find_and_copy(u32 base, u32 lim) +static int nvram_find_and_copy(u32 base, u32 lim) { struct nvram_header *header; int i; @@ -49,7 +49,7 @@ static void nvram_find_and_copy(u32 base, u32 lim) if (header->magic == NVRAM_HEADER) goto found; - return; + return -ENXIO; found: src = (u32 *) header; @@ -58,10 +58,12 @@ found: *dst++ = *src++; for (; i < header->len && i < NVRAM_SPACE; i += 4) *dst++ = le32_to_cpu(*src++); + + return 0; } #ifdef CONFIG_BCM47XX_SSB -static void nvram_init_ssb(void) +static int nvram_init_ssb(void) { struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; u32 base; @@ -72,15 +74,15 @@ static void nvram_init_ssb(void) lim = mcore->pflash.window_size; } else { pr_err("Couldn't find supported flash memory\n"); - return; + return -ENXIO; } - nvram_find_and_copy(base, lim); + return nvram_find_and_copy(base, lim); } #endif #ifdef CONFIG_BCM47XX_BCMA -static void nvram_init_bcma(void) +static int nvram_init_bcma(void) { struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc; u32 base; @@ -96,38 +98,41 @@ static void nvram_init_bcma(void) #endif } else { pr_err("Couldn't find supported flash memory\n"); - return; + return -ENXIO; } - nvram_find_and_copy(base, lim); + return nvram_find_and_copy(base, lim); } #endif -static void early_nvram_init(void) +static int early_nvram_init(void) { switch (bcm47xx_bus_type) { #ifdef CONFIG_BCM47XX_SSB case BCM47XX_BUS_TYPE_SSB: - nvram_init_ssb(); - break; + return nvram_init_ssb(); #endif #ifdef CONFIG_BCM47XX_BCMA case BCM47XX_BUS_TYPE_BCMA: - nvram_init_bcma(); - break; + return nvram_init_bcma(); #endif } + return -ENXIO; } int nvram_getenv(char *name, char *val, size_t val_len) { char *var, *value, *end, *eq; + int err; if (!name) return -EINVAL; - if (!nvram_buf[0]) - early_nvram_init(); + if (!nvram_buf[0]) { + err = early_nvram_init(); + if (err) + return err; + } /* Look for name=value and return value */ var = &nvram_buf[sizeof(struct nvram_header)]; -- cgit v1.2.3-59-g8ed1b From c4485671fbbb6fc453c2fb2dbb4bfc374770b0e7 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:11 +0000 Subject: MIPS: BCM47XX: nvram add nand flash support Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4741/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 80e352e0c995..42e527121314 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -30,6 +30,7 @@ static int nvram_find_and_copy(u32 base, u32 lim) u32 off; u32 *src, *dst; + /* TODO: when nvram is on nand flash check for bad blocks first. */ off = FLASH_MIN; while (off <= lim) { /* Windowed flash access */ @@ -88,6 +89,12 @@ static int nvram_init_bcma(void) u32 base; u32 lim; +#ifdef CONFIG_BCMA_NFLASH + if (cc->nflash.boot) { + base = BCMA_SOC_FLASH1; + lim = BCMA_SOC_FLASH1_SZ; + } else +#endif if (cc->pflash.present) { base = cc->pflash.window; lim = cc->pflash.window_size; -- cgit v1.2.3-59-g8ed1b From e58da16f716c0e7822e64a5d8a1f413041bc912e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:12 +0000 Subject: MIPS: BCM47XX: rename early_nvram_init to nvram_init Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4742/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 42e527121314..6cf3ef29d844 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -112,7 +112,7 @@ static int nvram_init_bcma(void) } #endif -static int early_nvram_init(void) +static int nvram_init(void) { switch (bcm47xx_bus_type) { #ifdef CONFIG_BCM47XX_SSB @@ -136,7 +136,7 @@ int nvram_getenv(char *name, char *val, size_t val_len) return -EINVAL; if (!nvram_buf[0]) { - err = early_nvram_init(); + err = nvram_init(); if (err) return err; } -- cgit v1.2.3-59-g8ed1b From f36738ddfeea02867b393e7f34da0cec48bafc54 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:13 +0000 Subject: MIPS: BCM47XX: handle different nvram sizes The old code just worked for nvram with a size of 0x8000 bytes. This patch adds support for reading nvram from partitions of 0xF000 and 0x10000 bytes. There is just 32KB space for the nvram, but most devices do not use the full size and this code reads the first 32KB in that case and prints a warning. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4743/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 6cf3ef29d844..b4a47fcb4f64 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -3,7 +3,7 @@ * * Copyright (C) 2005 Broadcom Corporation * Copyright (C) 2006 Felix Fietkau - * Copyright (C) 2010-2011 Hauke Mehrtens + * Copyright (C) 2010-2012 Hauke Mehrtens * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -23,42 +23,74 @@ static char nvram_buf[NVRAM_SPACE]; +static u32 find_nvram_size(u32 end) +{ + struct nvram_header *header; + u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; + int i; + + for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { + header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]); + if (header->magic == NVRAM_HEADER) + return nvram_sizes[i]; + } + + return 0; +} + +/* Probe for NVRAM header */ static int nvram_find_and_copy(u32 base, u32 lim) { struct nvram_header *header; int i; u32 off; u32 *src, *dst; + u32 size; /* TODO: when nvram is on nand flash check for bad blocks first. */ off = FLASH_MIN; while (off <= lim) { /* Windowed flash access */ - header = (struct nvram_header *) - KSEG1ADDR(base + off - NVRAM_SPACE); - if (header->magic == NVRAM_HEADER) + size = find_nvram_size(base + off); + if (size) { + header = (struct nvram_header *)KSEG1ADDR(base + off - + size); goto found; + } off <<= 1; } /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ header = (struct nvram_header *) KSEG1ADDR(base + 4096); - if (header->magic == NVRAM_HEADER) + if (header->magic == NVRAM_HEADER) { + size = NVRAM_SPACE; goto found; + } header = (struct nvram_header *) KSEG1ADDR(base + 1024); - if (header->magic == NVRAM_HEADER) + if (header->magic == NVRAM_HEADER) { + size = NVRAM_SPACE; goto found; + } + pr_err("no nvram found\n"); return -ENXIO; found: + + if (header->len > size) + pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n"); + if (header->len > NVRAM_SPACE) + pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", + header->len, NVRAM_SPACE); + src = (u32 *) header; dst = (u32 *) nvram_buf; for (i = 0; i < sizeof(struct nvram_header); i += 4) *dst++ = *src++; - for (; i < header->len && i < NVRAM_SPACE; i += 4) + for (; i < header->len && i < NVRAM_SPACE && i < size; i += 4) *dst++ = le32_to_cpu(*src++); + memset(dst, 0x0, NVRAM_SPACE - i); return 0; } -- cgit v1.2.3-59-g8ed1b From 111bd981e2216827aab95503596501ab71bc7a7d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:51:14 +0000 Subject: MIPS: BCM47XX: add bcm47xx prefix in front of nvram function names The nvram functions are exported and used by some normal drivers. To prevent name clashes with ofter parts of the kernel code add a bcm47xx_ prefix in front of the function names and the header file name. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4744/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/nvram.c | 6 +-- arch/mips/bcm47xx/setup.c | 6 +-- arch/mips/bcm47xx/sprom.c | 8 ++-- arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 51 ++++++++++++++++++++++ arch/mips/include/asm/mach-bcm47xx/nvram.h | 51 ---------------------- drivers/mtd/bcm47xxpart.c | 2 +- drivers/net/ethernet/broadcom/b44.c | 4 +- drivers/ssb/driver_chipcommon_pmu.c | 4 +- include/linux/ssb/ssb_driver_gige.h | 6 +-- 9 files changed, 69 insertions(+), 69 deletions(-) create mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h delete mode 100644 arch/mips/include/asm/mach-bcm47xx/nvram.h diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index b4a47fcb4f64..e63bd5abd9a2 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include static char nvram_buf[NVRAM_SPACE]; @@ -159,7 +159,7 @@ static int nvram_init(void) return -ENXIO; } -int nvram_getenv(char *name, char *val, size_t val_len) +int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len) { char *var, *value, *end, *eq; int err; @@ -189,4 +189,4 @@ int nvram_getenv(char *name, char *val, size_t val_len) } return -ENOENT; } -EXPORT_SYMBOL(nvram_getenv); +EXPORT_SYMBOL(bcm47xx_nvram_getenv); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 4d54b58dbd32..b2246cd9ca12 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include union bcm47xx_bus bcm47xx_bus; EXPORT_SYMBOL(bcm47xx_bus); @@ -115,7 +115,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, memset(&iv->sprom, 0, sizeof(struct ssb_sprom)); bcm47xx_fill_sprom(&iv->sprom, NULL, false); - if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) + if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); return 0; @@ -138,7 +138,7 @@ static void __init bcm47xx_register_ssb(void) panic("Failed to initialize SSB bus (err %d)", err); mcore = &bcm47xx_bus.ssb.mipscore; - if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) { + if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) { if (strstr(buf, "console=ttyS1")) { struct ssb_serial_port port; diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 66b71c363300..89b9bf46b13b 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -27,7 +27,7 @@ */ #include -#include +#include static void create_key(const char *prefix, const char *postfix, const char *name, char *buf, int len) @@ -50,10 +50,10 @@ static int get_nvram_var(const char *prefix, const char *postfix, create_key(prefix, postfix, name, key, sizeof(key)); - err = nvram_getenv(key, buf, len); + err = bcm47xx_nvram_getenv(key, buf, len); if (fallback && err == -ENOENT && prefix) { create_key(NULL, postfix, name, key, sizeof(key)); - err = nvram_getenv(key, buf, len); + err = bcm47xx_nvram_getenv(key, buf, len); } return err; } @@ -144,7 +144,7 @@ static void nvram_read_macaddr(const char *prefix, const char *name, if (err < 0) return; - nvram_parse_macaddr(buf, *val); + bcm47xx_nvram_parse_macaddr(buf, *val); } static void nvram_read_alpha2(const char *prefix, const char *name, diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h new file mode 100644 index 000000000000..b8e7be8f34dd --- /dev/null +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2005, Broadcom Corporation + * Copyright (C) 2006, Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __BCM47XX_NVRAM_H +#define __BCM47XX_NVRAM_H + +#include +#include + +struct nvram_header { + u32 magic; + u32 len; + u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + u32 config_ncdl; /* ncdl values for memc */ +}; + +#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +#define NVRAM_SPACE 0x8000 + +#define FLASH_MIN 0x00020000 /* Minimum flash size */ + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len); + +static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6]) +{ + if (strchr(buf, ':')) + sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else if (strchr(buf, '-')) + sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else + printk(KERN_WARNING "Can not parse mac address: %s\n", buf); +} + +#endif /* __BCM47XX_NVRAM_H */ diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h deleted file mode 100644 index 550a7fc932c9..000000000000 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2005, Broadcom Corporation - * Copyright (C) 2006, Felix Fietkau - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef __NVRAM_H -#define __NVRAM_H - -#include -#include - -struct nvram_header { - u32 magic; - u32 len; - u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ - u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ - u32 config_ncdl; /* ncdl values for memc */ -}; - -#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ -#define NVRAM_VERSION 1 -#define NVRAM_HEADER_SIZE 20 -#define NVRAM_SPACE 0x8000 - -#define FLASH_MIN 0x00020000 /* Minimum flash size */ - -#define NVRAM_MAX_VALUE_LEN 255 -#define NVRAM_MAX_PARAM_LEN 64 - -extern int nvram_getenv(char *name, char *val, size_t val_len); - -static inline void nvram_parse_macaddr(char *buf, u8 macaddr[6]) -{ - if (strchr(buf, ':')) - sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else if (strchr(buf, '-')) - sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else - printk(KERN_WARNING "Can not parse mac address: %s\n", buf); -} - -#endif diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index e06d782489a6..6a1180502cc1 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include /* 10 parts were found on sflash on Netgear WNDR4500 */ #define BCM47XXPART_MAX_PARTS 12 diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 219f6226fcb1..330b0908bf97 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -381,7 +381,7 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) } #ifdef CONFIG_BCM47XX -#include +#include static void b44_wap54g10_workaround(struct b44 *bp) { char buf[20]; @@ -393,7 +393,7 @@ static void b44_wap54g10_workaround(struct b44 *bp) * see https://dev.openwrt.org/ticket/146 * check and reset bit "isolate" */ - if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0) + if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0) return; if (simple_strtoul(buf, NULL, 0) == 2) { err = __b44_readphy(bp, 0, MII_BMCR, &val); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index a43415a7fbed..4c0f6d883dd3 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -14,7 +14,7 @@ #include #include #ifdef CONFIG_BCM47XX -#include +#include #endif #include "ssb_private.h" @@ -322,7 +322,7 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc) if (bus->bustype == SSB_BUSTYPE_SSB) { #ifdef CONFIG_BCM47XX char buf[20]; - if (nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0) + if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0) crystalfreq = simple_strtoul(buf, NULL, 0); #endif } diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h index 6b05dcd927ff..6d92a92573df 100644 --- a/include/linux/ssb/ssb_driver_gige.h +++ b/include/linux/ssb/ssb_driver_gige.h @@ -98,14 +98,14 @@ static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) } #ifdef CONFIG_BCM47XX -#include +#include /* Get the device MAC address */ static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) { char buf[20]; - if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0) + if (bcm47xx_nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0) return; - nvram_parse_macaddr(buf, macaddr); + bcm47xx_nvram_parse_macaddr(buf, macaddr); } #else static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) -- cgit v1.2.3-59-g8ed1b From 924ffb7dba80f44211d4ba08157496c6e37d307a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 19:53:26 +0000 Subject: MIPS: BCM47XX: trim the nvram values for parsing Some nvram values on some devices have a newline character at the end of the value, that caused read errors. Trim the string before reading the number. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4745/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/sprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 89b9bf46b13b..38492301a7b5 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -71,7 +71,7 @@ static void nvram_read_ ## type (const char *prefix, \ fallback); \ if (err < 0) \ return; \ - err = kstrto ## type (buf, 0, &var); \ + err = kstrto ## type(strim(buf), 0, &var); \ if (err) { \ pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \ prefix, name, postfix, buf, err); \ @@ -99,7 +99,7 @@ static void nvram_read_u32_2(const char *prefix, const char *name, err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); if (err < 0) return; - err = kstrtou32(buf, 0, &val); + err = kstrtou32(strim(buf), 0, &val); if (err) { pr_warn("can not parse nvram name %s%s with value %s got %i\n", prefix, name, buf, err); @@ -120,7 +120,7 @@ static void nvram_read_leddc(const char *prefix, const char *name, err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback); if (err < 0) return; - err = kstrtou32(buf, 0, &val); + err = kstrtou32(strim(buf), 0, &val); if (err) { pr_warn("can not parse nvram name %s%s with value %s got %i\n", prefix, name, buf, err); -- cgit v1.2.3-59-g8ed1b From fe08f8c2c5cf4fa95d9d6d7c1577c6fbb963b5c1 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 20:06:17 +0000 Subject: MIPS: BCM47XX: select BOOT_RAW All the boot loaders I have seen are booting the kernel in raw mode by default. CFE seems to support elf kernel images too, but the default case is raw for the devices I know of. Select this option to make the kernel boot on most of the devices with the default options. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4746/ Signed-off-by: John Crispin --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 2ac626ab9d43..c87455eedb8f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -107,6 +107,7 @@ config ATH79 config BCM47XX bool "Broadcom BCM47XX based boards" select ARCH_WANT_OPTIONAL_GPIOLIB + select BOOT_RAW select CEVT_R4K select CSRC_R4K select DMA_NONCOHERENT -- cgit v1.2.3-59-g8ed1b From dd54dedd947dd801ea60099837ac009eb235a61d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 26 Dec 2012 20:06:18 +0000 Subject: MIPS: BCM47XX: select NO_EXCEPT_FILL The kernel is loaded to 0x80001000 so there is some space left for the exception handlers and the kernel do not have to reserve some extra space for them. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4747/ Signed-off-by: John Crispin --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c87455eedb8f..daeafe26cfb2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -114,6 +114,7 @@ config BCM47XX select FW_CFE select HW_HAS_PCI select IRQ_CPU + select NO_EXCEPT_FILL select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK -- cgit v1.2.3-59-g8ed1b From 6404b7cb83273623dc836a33427a30e371dab11b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 6 Dec 2012 21:25:05 +0000 Subject: MIPS: BCM47XX: use fallback sprom var for board_{rev,type} An SoC normally do not define path variables for board_rev and board_type and the Broadcom SDK also uses the nvram values without a prefix in such cases. Do the same to fill these sprom attributes from nvram and do not leave them empty, because brcmsmac do not like this. Signed-off-by: Hauke Mehrtens Patchwork: http://patchwork.linux-mips.org/patch/4679/ Signed-off-by: John Crispin --- arch/mips/bcm47xx/sprom.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 38492301a7b5..7d97a5a4bd3f 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -652,12 +652,10 @@ static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix, bool fallback) { - nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0, - fallback); + nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0, true); nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0, fallback); - nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0, - fallback); + nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0, true); nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, &sprom->boardflags_hi, fallback); nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo, -- cgit v1.2.3-59-g8ed1b From 42f3caef039571df8c30a78a51c09cbdbaa7863b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 11 Jan 2013 22:44:10 +0100 Subject: MIPS: show correct cpu name for 24KEc Make sure 24KEc is properly identified inside /proc/cpuinfo Signed-off-by: John Crispin --- arch/mips/kernel/cpu-probe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index cce3782c96c9..9f31334ed1de 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -838,10 +838,13 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "MIPS 20Kc"; break; case PRID_IMP_24K: - case PRID_IMP_24KE: c->cputype = CPU_24K; __cpu_name[cpu] = "MIPS 24Kc"; break; + case PRID_IMP_24KE: + c->cputype = CPU_24K; + __cpu_name[cpu] = "MIPS 24KEc"; + break; case PRID_IMP_25KF: c->cputype = CPU_25KF; __cpu_name[cpu] = "MIPS 25Kc"; -- cgit v1.2.3-59-g8ed1b From 3d18c17e4f1699c3a4f47d2483c5d4c3ab3a242b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 19 Jan 2013 08:54:23 +0000 Subject: MIPS: lantiq: trivial typo fix "nodes" is written with a single "s" Signed-off-by: John Crispin Patchwork: http://patchwork.linux-mips.org/patch/4814/ --- arch/mips/lantiq/xway/sysctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 3925e6609acc..1aaa726aad47 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -305,7 +305,7 @@ void __init ltq_soc_init(void) /* check if all the core register ranges are available */ if (!np_pmu || !np_cgu || !np_ebu) - panic("Failed to load core nodess from devicetree"); + panic("Failed to load core nodes from devicetree"); if (of_address_to_resource(np_pmu, 0, &res_pmu) || of_address_to_resource(np_cgu, 0, &res_cgu) || -- cgit v1.2.3-59-g8ed1b From 740c606e8e79c3e3800afbc32b4e6123da403d6c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 19 Jan 2013 08:54:24 +0000 Subject: MIPS: lantiq: adds static clock for PP32 The Lantiq DSL SoCs have an internal networking processor. Add code to read the static clock rate. Signed-off-by: John Crispin Patchwork: http://patchwork.linux-mips.org/patch/4815/ --- arch/mips/include/asm/mach-lantiq/lantiq.h | 1 + arch/mips/lantiq/clk.c | 12 +++++++-- arch/mips/lantiq/clk.h | 7 ++++- arch/mips/lantiq/falcon/sysctrl.c | 4 +-- arch/mips/lantiq/xway/clk.c | 43 ++++++++++++++++++++++++++++++ arch/mips/lantiq/xway/sysctrl.c | 12 +++++---- 6 files changed, 69 insertions(+), 10 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h index 5e8a6e965756..76be7a09b9aa 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -41,6 +41,7 @@ extern void clk_deactivate(struct clk *clk); extern struct clk *clk_get_cpu(void); extern struct clk *clk_get_fpi(void); extern struct clk *clk_get_io(void); +extern struct clk *clk_get_ppe(void); /* find out what bootsource we have */ extern unsigned char ltq_boot_select(void); diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c index ce2f129b081f..d90356004027 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -26,13 +26,15 @@ #include "prom.h" /* lantiq socs have 3 static clocks */ -static struct clk cpu_clk_generic[3]; +static struct clk cpu_clk_generic[4]; -void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) +void clkdev_add_static(unsigned long cpu, unsigned long fpi, + unsigned long io, unsigned long ppe) { cpu_clk_generic[0].rate = cpu; cpu_clk_generic[1].rate = fpi; cpu_clk_generic[2].rate = io; + cpu_clk_generic[3].rate = ppe; } struct clk *clk_get_cpu(void) @@ -51,6 +53,12 @@ struct clk *clk_get_io(void) return &cpu_clk_generic[2]; } +struct clk *clk_get_ppe(void) +{ + return &cpu_clk_generic[3]; +} +EXPORT_SYMBOL_GPL(clk_get_ppe); + static inline int clk_good(struct clk *clk) { return clk && !IS_ERR(clk); diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h index fa670602b91b..77e4bdb1fe8c 100644 --- a/arch/mips/lantiq/clk.h +++ b/arch/mips/lantiq/clk.h @@ -27,12 +27,15 @@ #define CLOCK_167M 166666667 #define CLOCK_196_608M 196608000 #define CLOCK_200M 200000000 +#define CLOCK_222M 222000000 +#define CLOCK_240M 240000000 #define CLOCK_250M 250000000 #define CLOCK_266M 266666666 #define CLOCK_300M 300000000 #define CLOCK_333M 333333333 #define CLOCK_393M 393215332 #define CLOCK_400M 400000000 +#define CLOCK_450M 450000000 #define CLOCK_500M 500000000 #define CLOCK_600M 600000000 @@ -64,15 +67,17 @@ struct clk { }; extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, - unsigned long io); + unsigned long io, unsigned long ppe); extern unsigned long ltq_danube_cpu_hz(void); extern unsigned long ltq_danube_fpi_hz(void); +extern unsigned long ltq_danube_pp32_hz(void); extern unsigned long ltq_ar9_cpu_hz(void); extern unsigned long ltq_ar9_fpi_hz(void); extern unsigned long ltq_vr9_cpu_hz(void); extern unsigned long ltq_vr9_fpi_hz(void); +extern unsigned long ltq_vr9_pp32_hz(void); #endif diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c index 2d4ced332b37..ff4894a833ee 100644 --- a/arch/mips/lantiq/falcon/sysctrl.c +++ b/arch/mips/lantiq/falcon/sysctrl.c @@ -241,9 +241,9 @@ void __init ltq_soc_init(void) /* get our 3 static rates for cpu, fpi and io clocks */ if (ltq_sys1_r32(SYS1_CPU0CC) & CPU0CC_CPUDIV) - clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M); + clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M, 0); else - clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M); + clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M, 0); /* add our clock domains */ clkdev_add_sys("1d810000.gpio", SYSCTL_SYSETH, ACTS_P0); diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c index 9aa17f79a742..1ab576dc9bd1 100644 --- a/arch/mips/lantiq/xway/clk.c +++ b/arch/mips/lantiq/xway/clk.c @@ -53,6 +53,29 @@ unsigned long ltq_danube_cpu_hz(void) } } +unsigned long ltq_danube_pp32_hz(void) +{ + unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 7) & 3; + unsigned long clk; + + switch (clksys) { + case 1: + clk = CLOCK_240M; + break; + case 2: + clk = CLOCK_222M; + break; + case 3: + clk = CLOCK_133M; + break; + default: + clk = CLOCK_266M; + break; + } + + return clk; +} + unsigned long ltq_ar9_sys_hz(void) { if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2) @@ -149,3 +172,23 @@ unsigned long ltq_vr9_fpi_hz(void) return clk; } + +unsigned long ltq_vr9_pp32_hz(void) +{ + unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 3; + unsigned long clk; + + switch (clksys) { + case 1: + clk = CLOCK_450M; + break; + case 2: + clk = CLOCK_300M; + break; + default: + clk = CLOCK_500M; + break; + } + + return clk; +} diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 1aaa726aad47..3390fcd6ee56 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -356,14 +356,16 @@ void __init ltq_soc_init(void) if (of_machine_is_compatible("lantiq,ase")) { if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) - clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); + clkdev_add_static(CLOCK_266M, CLOCK_133M, + CLOCK_133M, CLOCK_266M); else - clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); + clkdev_add_static(CLOCK_133M, CLOCK_133M, + CLOCK_133M, CLOCK_133M); clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY), clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY); } else if (of_machine_is_compatible("lantiq,vr9")) { clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), - ltq_vr9_fpi_hz()); + ltq_vr9_fpi_hz(), ltq_vr9_pp32_hz()); clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY); clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK); clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI); @@ -376,10 +378,10 @@ void __init ltq_soc_init(void) PMU_PPE_QSB | PMU_PPE_TOP); } else if (of_machine_is_compatible("lantiq,ar9")) { clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), - ltq_ar9_fpi_hz()); + ltq_ar9_fpi_hz(), CLOCK_250M); clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH); } else { clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_fpi_hz()); + ltq_danube_fpi_hz(), ltq_danube_pp32_hz()); } } -- cgit v1.2.3-59-g8ed1b From d0c550dc36881fda171ec8ad3dcc67491ad968eb Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 19 Jan 2013 08:54:25 +0000 Subject: MIPS: lantiq: add GPHY clock gate bits Explicitly enable the clock gate of the internal GPHYs found on xrx200. Signed-off-by: John Crispin Patchwork: http://patchwork.linux-mips.org/patch/4816/ --- arch/mips/lantiq/xway/reset.c | 9 +++++++++ arch/mips/lantiq/xway/sysctrl.c | 1 + 2 files changed, 10 insertions(+) diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index 544dbb7fb421..1fa0f175357e 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -78,10 +78,19 @@ static struct ltq_xrx200_gphy_reset { /* reset and boot a gphy. these phys only exist on xrx200 SoC */ int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr) { + struct clk *clk; + if (!of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200")) { dev_err(dev, "this SoC has no GPHY\n"); return -EINVAL; } + + clk = clk_get_sys("1f203000.rcu", "gphy"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + clk_enable(clk); + if (id > 1) { dev_err(dev, "%u is an invalid gphy id\n", id); return -EINVAL; diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 3390fcd6ee56..c24924fe087d 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -376,6 +376,7 @@ void __init ltq_soc_init(void) PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | PMU_PPE_QSB | PMU_PPE_TOP); + clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY); } else if (of_machine_is_compatible("lantiq,ar9")) { clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), ltq_ar9_fpi_hz(), CLOCK_250M); -- cgit v1.2.3-59-g8ed1b From bae696a267d81ea268f4de1e396b8c82154f22ed Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 19 Jan 2013 08:54:26 +0000 Subject: MIPS: lantiq: improve pci reset gpio handling We need to make sure that the reset gpio is available and also set a sane default state. Signed-off-by: John Crispin Patchwork: http://patchwork.linux-mips.org/patch/4817/ --- arch/mips/pci/pci-lantiq.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 95681789b51e..f32664bbbe17 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -129,8 +129,16 @@ static int ltq_pci_startup(struct platform_device *pdev) /* setup reset gpio used by pci */ reset_gpio = of_get_named_gpio(node, "gpio-reset", 0); - if (gpio_is_valid(reset_gpio)) - devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset"); + if (gpio_is_valid(reset_gpio)) { + int ret = devm_gpio_request(&pdev->dev, + reset_gpio, "pci-reset"); + if (ret) { + dev_err(&pdev->dev, + "failed to request gpio %d\n", reset_gpio); + return ret; + } + gpio_direction_output(reset_gpio, 1); + } /* enable auto-switching between PCI and EBU */ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); -- cgit v1.2.3-59-g8ed1b From 26365625947fb7d6501065272a1fd59460c0f4ed Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 19 Jan 2013 08:54:27 +0000 Subject: MIPS: lantiq: rework external irq code This code makes the irqs used by the EIU loadable from the DT. Additionally we add a helper that allows the pinctrl layer to map external irqs to real irq numbers. Signed-off-by: John Crispin Patchwork: http://patchwork.linux-mips.org/patch/4818/ --- arch/mips/include/asm/mach-lantiq/lantiq.h | 1 + arch/mips/lantiq/irq.c | 105 ++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h index 76be7a09b9aa..f196cceb7322 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -34,6 +34,7 @@ extern spinlock_t ebu_lock; extern void ltq_disable_irq(struct irq_data *data); extern void ltq_mask_and_ack_irq(struct irq_data *data); extern void ltq_enable_irq(struct irq_data *data); +extern int ltq_eiu_get_irq(int exin); /* clock handling */ extern int clk_activate(struct clk *clk); diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index a7935bf0fecb..51194875f158 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -33,17 +33,10 @@ /* register definitions - external irqs */ #define LTQ_EIU_EXIN_C 0x0000 #define LTQ_EIU_EXIN_INIC 0x0004 +#define LTQ_EIU_EXIN_INC 0x0008 #define LTQ_EIU_EXIN_INEN 0x000C -/* irq numbers used by the external interrupt unit (EIU) */ -#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30) -#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31) -#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26) -#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0 -#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) -#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) -#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) -#define XWAY_EXIN_COUNT 3 +/* number of external interrupts */ #define MAX_EIU 6 /* the performance counter */ @@ -72,20 +65,19 @@ int gic_present; #endif -static unsigned short ltq_eiu_irq[MAX_EIU] = { - LTQ_EIU_IR0, - LTQ_EIU_IR1, - LTQ_EIU_IR2, - LTQ_EIU_IR3, - LTQ_EIU_IR4, - LTQ_EIU_IR5, -}; - static int exin_avail; +static struct resource ltq_eiu_irq[MAX_EIU]; static void __iomem *ltq_icu_membase[MAX_IM]; static void __iomem *ltq_eiu_membase; static struct irq_domain *ltq_domain; +int ltq_eiu_get_irq(int exin) +{ + if (exin < exin_avail) + return ltq_eiu_irq[exin].start; + return -1; +} + void ltq_disable_irq(struct irq_data *d) { u32 ier = LTQ_ICU_IM0_IER; @@ -128,19 +120,65 @@ void ltq_enable_irq(struct irq_data *d) ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier); } +static int ltq_eiu_settype(struct irq_data *d, unsigned int type) +{ + int i; + + for (i = 0; i < MAX_EIU; i++) { + if (d->hwirq == ltq_eiu_irq[i].start) { + int val = 0; + int edge = 0; + + switch (type) { + case IRQF_TRIGGER_NONE: + break; + case IRQF_TRIGGER_RISING: + val = 1; + edge = 1; + break; + case IRQF_TRIGGER_FALLING: + val = 2; + edge = 1; + break; + case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: + val = 3; + edge = 1; + break; + case IRQF_TRIGGER_HIGH: + val = 5; + break; + case IRQF_TRIGGER_LOW: + val = 6; + break; + default: + pr_err("invalid type %d for irq %ld\n", + type, d->hwirq); + return -EINVAL; + } + + if (edge) + irq_set_handler(d->hwirq, handle_edge_irq); + + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | + (val << (i * 4)), LTQ_EIU_EXIN_C); + } + } + + return 0; +} + static unsigned int ltq_startup_eiu_irq(struct irq_data *d) { int i; ltq_enable_irq(d); for (i = 0; i < MAX_EIU; i++) { - if (d->hwirq == ltq_eiu_irq[i]) { - /* low level - we should really handle set_type */ - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | - (0x6 << (i * 4)), LTQ_EIU_EXIN_C); + if (d->hwirq == ltq_eiu_irq[i].start) { + /* by default we are low level triggered */ + ltq_eiu_settype(d, IRQF_TRIGGER_LOW); /* clear all pending */ - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i), - LTQ_EIU_EXIN_INIC); + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i), + LTQ_EIU_EXIN_INC); /* enable */ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), LTQ_EIU_EXIN_INEN); @@ -157,7 +195,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d) ltq_disable_irq(d); for (i = 0; i < MAX_EIU; i++) { - if (d->hwirq == ltq_eiu_irq[i]) { + if (d->hwirq == ltq_eiu_irq[i].start) { /* disable */ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), LTQ_EIU_EXIN_INEN); @@ -186,6 +224,7 @@ static struct irq_chip ltq_eiu_type = { .irq_ack = ltq_ack_irq, .irq_mask = ltq_disable_irq, .irq_mask_ack = ltq_mask_and_ack_irq, + .irq_set_type = ltq_eiu_settype, }; static void ltq_hw_irqdispatch(int module) @@ -301,7 +340,7 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) return 0; for (i = 0; i < exin_avail; i++) - if (hw == ltq_eiu_irq[i]) + if (hw == ltq_eiu_irq[i].start) chip = <q_eiu_type; irq_set_chip_and_handler(hw, chip, handle_level_irq); @@ -323,7 +362,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) { struct device_node *eiu_node; struct resource res; - int i; + int i, ret; for (i = 0; i < MAX_IM; i++) { if (of_address_to_resource(node, i, &res)) @@ -340,17 +379,19 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) } /* the external interrupts are optional and xway only */ - eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu"); + eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { /* find out how many external irq sources we have */ - const __be32 *count = of_get_property(node, - "lantiq,count", NULL); + exin_avail = of_irq_count(eiu_node); - if (count) - exin_avail = *count; if (exin_avail > MAX_EIU) exin_avail = MAX_EIU; + ret = of_irq_to_resource_table(eiu_node, + ltq_eiu_irq, exin_avail); + if (ret != exin_avail) + panic("failed to load external irq resources\n"); + if (request_mem_region(res.start, resource_size(&res), res.name) < 0) pr_err("Failed to request eiu memory"); -- cgit v1.2.3-59-g8ed1b From f0cb40e5c384cf2cc4b2b932b61474544ac1fc9a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:53 +0000 Subject: MIPS: Netlogic: add XLS6xx to FMN config Add support for XLS6xx CPUs to the Fast Message Network (FMN) configuration. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4785/ Signed-off-by: John Crispin --- arch/mips/netlogic/xlr/fmn-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/netlogic/xlr/fmn-config.c b/arch/mips/netlogic/xlr/fmn-config.c index bed2cffa1008..e8071d6e8553 100644 --- a/arch/mips/netlogic/xlr/fmn-config.c +++ b/arch/mips/netlogic/xlr/fmn-config.c @@ -216,6 +216,8 @@ void xlr_board_info_setup(void) case PRID_IMP_NETLOGIC_XLS404B: case PRID_IMP_NETLOGIC_XLS408B: case PRID_IMP_NETLOGIC_XLS416B: + case PRID_IMP_NETLOGIC_XLS608B: + case PRID_IMP_NETLOGIC_XLS616B: setup_fmn_cc(&gmac[0], FMN_STNID_GMAC0, FMN_STNID_GMAC0_TX3, 8, 8, 32); setup_fmn_cc(&gmac[1], FMN_STNID_GMAC1_FR_0, -- cgit v1.2.3-59-g8ed1b From 220d9122e8c5a467fdeefc1857e077f29a623bfd Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:54 +0000 Subject: MIPS: Netlogic: Optimize EIMR/EIRR accesses in 32-bit Provide functions ack_c0_eirr(), set_c0_eimr(), clear_c0_eimr() and read_c0_eirr_and_eimr() that do the EIMR and EIRR operations and update the interrupt handling code to use these functions. Also, use the EIMR register functions to mask interrupts in the irq code. The 64-bit interrupt request and mask registers (EIRR and EIMR) are accessed when the interrupts are off, and the common operations are to set or clear a bit in these registers. Using the 64-bit c0 access functions for these operations is not optimal in 32-bit, because it will disable/restore interrupts and split/join the 64-bit value during each register access. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4790/ Signed-off-by: John Crispin --- arch/mips/include/asm/netlogic/mips-extns.h | 79 +++++++++++++++++++++++++++++ arch/mips/netlogic/common/irq.c | 39 +++++--------- arch/mips/netlogic/common/smp.c | 8 ++- 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h index 32ba6d95d47c..cc4296595df5 100644 --- a/arch/mips/include/asm/netlogic/mips-extns.h +++ b/arch/mips/include/asm/netlogic/mips-extns.h @@ -68,6 +68,85 @@ do { \ __write_64bit_c0_register($9, 7, (val)); \ } while (0) +/* + * Handling the 64 bit EIMR and EIRR registers in 32-bit mode with + * standard functions will be very inefficient. This provides + * optimized functions for the normal operations on the registers. + * + * Call with interrupts disabled. + */ +static inline void ack_c0_eirr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv $1, $1, %0\n\t" + "dmtc0 $1, $9, 6\n\t" + ".set pop" + : : "r" (irq)); +} + +static inline void set_c0_eimr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv %0, $1, %0\n\t" + "dmfc0 $1, $9, 7\n\t" + "or $1, %0\n\t" + "dmtc0 $1, $9, 7\n\t" + ".set pop" + : "+r" (irq)); +} + +static inline void clear_c0_eimr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv %0, $1, %0\n\t" + "dmfc0 $1, $9, 7\n\t" + "or $1, %0\n\t" + "xor $1, %0\n\t" + "dmtc0 $1, $9, 7\n\t" + ".set pop" + : "+r" (irq)); +} + +/* + * Read c0 eimr and c0 eirr, do AND of the two values, the result is + * the interrupts which are raised and are not masked. + */ +static inline uint64_t read_c0_eirr_and_eimr(void) +{ + uint64_t val; + +#ifdef CONFIG_64BIT + val = read_c0_eimr() & read_c0_eirr(); +#else + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "dmfc0 %M0, $9, 6\n\t" + "dmfc0 %L0, $9, 7\n\t" + "and %M0, %L0\n\t" + "dsll %L0, %M0, 32\n\t" + "dsra %M0, %M0, 32\n\t" + "dsra %L0, %L0, 32\n\t" + ".set pop" + : "=r" (val)); +#endif + + return val; +} + static inline int hard_smp_processor_id(void) { return __read_32bit_c0_register($15, 1) & 0x3ff; diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 00dcc7a2bc5a..d42cd1a2a124 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -105,21 +105,23 @@ static void xlp_pic_disable(struct irq_data *d) static void xlp_pic_mask_ack(struct irq_data *d) { struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); - uint64_t mask = 1ull << pd->picirq; - write_c0_eirr(mask); /* ack by writing EIRR */ + clear_c0_eimr(pd->picirq); + ack_c0_eirr(pd->picirq); } static void xlp_pic_unmask(struct irq_data *d) { struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); - if (!pd) - return; + BUG_ON(!pd); if (pd->extra_ack) pd->extra_ack(d); + /* re-enable the intr on this cpu */ + set_c0_eimr(pd->picirq); + /* Ack is a single write, no need to lock */ nlm_pic_ack(pd->node->picbase, pd->irt); } @@ -134,32 +136,17 @@ static struct irq_chip xlp_pic = { static void cpuintr_disable(struct irq_data *d) { - uint64_t eimr; - uint64_t mask = 1ull << d->irq; - - eimr = read_c0_eimr(); - write_c0_eimr(eimr & ~mask); + clear_c0_eimr(d->irq); } static void cpuintr_enable(struct irq_data *d) { - uint64_t eimr; - uint64_t mask = 1ull << d->irq; - - eimr = read_c0_eimr(); - write_c0_eimr(eimr | mask); + set_c0_eimr(d->irq); } static void cpuintr_ack(struct irq_data *d) { - uint64_t mask = 1ull << d->irq; - - write_c0_eirr(mask); -} - -static void cpuintr_nop(struct irq_data *d) -{ - WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); + ack_c0_eirr(d->irq); } /* @@ -170,9 +157,9 @@ struct irq_chip nlm_cpu_intr = { .name = "XLP-CPU-INTR", .irq_enable = cpuintr_enable, .irq_disable = cpuintr_disable, - .irq_mask = cpuintr_nop, - .irq_ack = cpuintr_nop, - .irq_eoi = cpuintr_ack, + .irq_mask = cpuintr_disable, + .irq_ack = cpuintr_ack, + .irq_eoi = cpuintr_enable, }; static void __init nlm_init_percpu_irqs(void) @@ -265,7 +252,7 @@ asmlinkage void plat_irq_dispatch(void) int i, node; node = nlm_nodeid(); - eirr = read_c0_eirr() & read_c0_eimr(); + eirr = read_c0_eirr_and_eimr(); i = __ilog2_u64(eirr); if (i == -1) diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index a080d9ee3cd7..2bb95dcfe20a 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -84,15 +84,19 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) /* IRQ_IPI_SMP_FUNCTION Handler */ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) { - write_c0_eirr(1ull << irq); + clear_c0_eimr(irq); + ack_c0_eirr(irq); smp_call_function_interrupt(); + set_c0_eimr(irq); } /* IRQ_IPI_SMP_RESCHEDULE handler */ void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) { - write_c0_eirr(1ull << irq); + clear_c0_eimr(irq); + ack_c0_eirr(irq); scheduler_ipi(); + set_c0_eimr(irq); } /* -- cgit v1.2.3-59-g8ed1b From a264b5e8dc3cae1b07cea010d6283be6e67b0209 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 16 Jan 2013 11:12:40 +0000 Subject: MIPS: PCI: Byteswap not needed in little-endian mode Rename function xlp_enable_pci_bswap() to xlp_config_pci_bswap(), which is a better description for its functionality. When compiled in big-endian mode, xlp_config_pci_bswap() will configure the PCIe links to byteswap. In little-endian mode, no swap configuration is needed for the PCIe controller, and the function is empty. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4802/ Signed-off-by: John Crispin --- arch/mips/pci/pci-xlp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 140557a20488..5077148bd67d 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c @@ -191,7 +191,13 @@ int pcibios_plat_dev_init(struct pci_dev *dev) return 0; } -static int xlp_enable_pci_bswap(void) +/* + * If big-endian, enable hardware byteswap on the PCIe bridges. + * This will make both the SoC and PCIe devices behave consistently with + * readl/writel. + */ +#ifdef __BIG_ENDIAN +static void xlp_config_pci_bswap(void) { uint64_t pciebase, sysbase; int node, i; @@ -222,8 +228,11 @@ static int xlp_enable_pci_bswap(void) reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i); nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); } - return 0; } +#else +/* Swap configuration not needed in little-endian mode */ +static inline void xlp_config_pci_bswap(void) {} +#endif /* __BIG_ENDIAN */ static int __init pcibios_init(void) { @@ -235,7 +244,7 @@ static int __init pcibios_init(void) ioport_resource.start = 0; ioport_resource.end = ~0; - xlp_enable_pci_bswap(); + xlp_config_pci_bswap(); set_io_port_base(CKSEG1); nlm_pci_controller.io_map_base = CKSEG1; -- cgit v1.2.3-59-g8ed1b From a69ba6293d11b7dfd395a742f3449d6ddda8ecad Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:56 +0000 Subject: MIPS: Netlogic: Split XLP L1 i-cache among threads Since we now use r4k cache code for Netlogic XLP, it is better to split L1 icache among the active threads, so that threads won't step on each other while flushing icache. The L1 dcache is already split among the threads in the core. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4787/ Signed-off-by: John Crispin --- arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h | 2 ++ arch/mips/netlogic/common/smpboot.S | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h index 7b63a6b722a0..6d2e58a9a542 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h @@ -46,6 +46,8 @@ #define CPU_BLOCKID_FPU 9 #define CPU_BLOCKID_MAP 10 +#define ICU_DEFEATURE 0x100 + #define LSU_DEFEATURE 0x304 #define LSU_DEBUG_ADDR 0x305 #define LSU_DEBUG_DATA0 0x306 diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index a0b74874bebe..d772a87fe846 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -69,6 +69,12 @@ #endif mtcr t1, t0 + li t0, ICU_DEFEATURE + mfcr t1, t0 + ori t1, 0x1000 /* Enable Icache partitioning */ + mtcr t1, t0 + + #ifdef XLP_AX_WORKAROUND li t0, SCHED_DEFEATURE lui t1, 0x0100 /* Disable BRU accepting ALU ops */ -- cgit v1.2.3-59-g8ed1b From 4e45e542cd742c1c3e30e7f252640644c66548b5 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:57 +0000 Subject: MIPS: Netlogic: Use PIC timer as a clocksource The XLR/XLS/XLP PIC has a 8 countdown timers which run at the PIC frequencey. One of these can be used as a clocksource to provide timestamps that is common across cores. This can be used in place of the count/compare clocksource which is per-CPU. On XLR/XLS PIC registers are 32-bit, so we just use the lower 32-bits of the PIC counter. On XLP, the whole 64-bit can be used. Provide common macros and functions for PIC timer registers on XLR/XLS and XLP, and use them to register a PIC clocksource. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4786/ Signed-off-by: John Crispin --- arch/mips/include/asm/netlogic/xlp-hal/pic.h | 12 +++++-- arch/mips/include/asm/netlogic/xlr/pic.h | 48 +++++++++++++++++++++++-- arch/mips/netlogic/common/irq.c | 2 +- arch/mips/netlogic/common/time.c | 52 ++++++++++++++++++++++++++++ arch/mips/netlogic/xlr/platform.c | 2 +- arch/mips/netlogic/xlr/setup.c | 2 +- 6 files changed, 110 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h index b2e53a5383ab..ea6768c3e9f8 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h @@ -261,6 +261,8 @@ #define PIC_LOCAL_SCHEDULING 1 #define PIC_GLOBAL_SCHEDULING 0 +#define PIC_CLK_HZ 133333333 + #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) #define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) @@ -315,6 +317,12 @@ nlm_pic_read_timer(uint64_t base, int timer) return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); } +static inline uint32_t +nlm_pic_read_timer32(uint64_t base, int timer) +{ + return (uint32_t)nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); +} + static inline void nlm_pic_write_timer(uint64_t base, int timer, uint64_t value) { @@ -376,9 +384,9 @@ nlm_pic_ack(uint64_t base, int irt_num) } static inline void -nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en) { - nlm_pic_write_irt_direct(base, irt, 0, 0, 0, irq, hwt); + nlm_pic_write_irt_direct(base, irt, en, 0, 0, irq, hwt); } int nlm_irq_to_irt(int irq); diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h index 9a691b1f91ba..effa3377ded5 100644 --- a/arch/mips/include/asm/netlogic/xlr/pic.h +++ b/arch/mips/include/asm/netlogic/xlr/pic.h @@ -35,10 +35,11 @@ #ifndef _ASM_NLM_XLR_PIC_H #define _ASM_NLM_XLR_PIC_H -#define PIC_CLKS_PER_SEC 66666666ULL +#define PIC_CLK_HZ 66666666 /* PIC hardware interrupt numbers */ #define PIC_IRT_WD_INDEX 0 #define PIC_IRT_TIMER_0_INDEX 1 +#define PIC_IRT_TIMER_INDEX(i) ((i) + PIC_IRT_TIMER_0_INDEX) #define PIC_IRT_TIMER_1_INDEX 2 #define PIC_IRT_TIMER_2_INDEX 3 #define PIC_IRT_TIMER_3_INDEX 4 @@ -99,6 +100,7 @@ /* PIC Registers */ #define PIC_CTRL 0x00 +#define PIC_CTRL_STE 8 /* timer enable start bit */ #define PIC_IPI 0x04 #define PIC_INT_ACK 0x06 @@ -251,12 +253,52 @@ nlm_pic_ack(uint64_t base, int irt) } static inline void -nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en) { nlm_write_reg(base, PIC_IRT_0(irt), (1u << hwt)); /* local scheduling, invalid, level by default */ nlm_write_reg(base, PIC_IRT_1(irt), - (1 << 30) | (1 << 6) | irq); + (en << 30) | (1 << 6) | irq); +} + +static inline uint64_t +nlm_pic_read_timer(uint64_t base, int timer) +{ + uint32_t up1, up2, low; + + up1 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer)); + low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); + up2 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer)); + + if (up1 != up2) /* wrapped, get the new low */ + low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); + return ((uint64_t)up2 << 32) | low; + +} + +static inline uint32_t +nlm_pic_read_timer32(uint64_t base, int timer) +{ + return nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); +} + +static inline void +nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu) +{ + uint32_t up, low; + uint64_t pic_ctrl = nlm_read_reg(base, PIC_CTRL); + int en; + + en = (irq > 0); + up = value >> 32; + low = value & 0xFFFFFFFF; + nlm_write_reg(base, PIC_TIMER_MAXVAL_0(timer), low); + nlm_write_reg(base, PIC_TIMER_MAXVAL_1(timer), up); + nlm_pic_init_irt(base, PIC_IRT_TIMER_INDEX(timer), irq, cpu, 0); + + /* enable the timer */ + pic_ctrl |= (1 << (PIC_CTRL_STE + timer)); + nlm_write_reg(base, PIC_CTRL, pic_ctrl); } #endif #endif /* _ASM_NLM_XLR_PIC_H */ diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index d42cd1a2a124..642f1e4c2717 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -217,7 +217,7 @@ static void nlm_init_node_irqs(int node) nlm_setup_pic_irq(node, i, i, irt); /* set interrupts to first cpu in node */ nlm_pic_init_irt(nodep->picbase, irt, i, - node * NLM_CPUS_PER_NODE); + node * NLM_CPUS_PER_NODE, 0); irqmask |= (1ull << i); } nodep->irqmask = irqmask; diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index bd3e498157ff..20f89bc0507f 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -35,16 +35,68 @@ #include #include +#include + #include #include +#include +#include + +#if defined(CONFIG_CPU_XLP) +#include +#include +#include +#elif defined(CONFIG_CPU_XLR) +#include +#include +#include +#else +#error "Unknown CPU" +#endif unsigned int __cpuinit get_c0_compare_int(void) { return IRQ_TIMER; } +static cycle_t nlm_get_pic_timer(struct clocksource *cs) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + return ~nlm_pic_read_timer(picbase, PIC_CLOCK_TIMER); +} + +static cycle_t nlm_get_pic_timer32(struct clocksource *cs) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + return ~nlm_pic_read_timer32(picbase, PIC_CLOCK_TIMER); +} + +static struct clocksource csrc_pic = { + .name = "PIC", + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void nlm_init_pic_timer(void) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); + if (current_cpu_data.cputype == CPU_XLR) { + csrc_pic.mask = CLOCKSOURCE_MASK(32); + csrc_pic.read = nlm_get_pic_timer32; + } else { + csrc_pic.mask = CLOCKSOURCE_MASK(64); + csrc_pic.read = nlm_get_pic_timer; + } + csrc_pic.rating = 1000; + clocksource_register_hz(&csrc_pic, PIC_CLK_HZ); +} + void __init plat_time_init(void) { + nlm_init_pic_timer(); mips_hpt_frequency = nlm_get_cpu_frequency(); pr_info("MIPS counter frequency [%ld]\n", (unsigned long)mips_hpt_frequency); diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 507230eeb768..ce838f951356 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -64,7 +64,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) .iotype = UPIO_MEM32, \ .flags = (UPF_SKIP_TEST | \ UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ - .uartclk = PIC_CLKS_PER_SEC, \ + .uartclk = PIC_CLK_HZ, \ .type = PORT_16550A, \ .serial_in = nlm_xlr_uart_in, \ .serial_out = nlm_xlr_uart_out, \ diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index c5ce6992ac4c..54b301c809e1 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -70,7 +70,7 @@ static void __init nlm_early_serial_setup(void) s.iotype = UPIO_MEM32; s.regshift = 2; s.irq = PIC_UART_0_IRQ; - s.uartclk = PIC_CLKS_PER_SEC; + s.uartclk = PIC_CLK_HZ; s.serial_in = nlm_xlr_uart_in; s.serial_out = nlm_xlr_uart_out; s.mapbase = uart_base; -- cgit v1.2.3-59-g8ed1b From 8cd3d64c5714de7e17eccde48837b329f67bd85e Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:58 +0000 Subject: MIPS: PCI: Prevent hang on XLP reg read Reading PCI extended register at 0x255 on a bridge will hang if there is no device connected on the link. Make PCI read routine skip this register. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4789/ Signed-off-by: John Crispin --- arch/mips/pci/pci-xlp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 5077148bd67d..fbf001a068a4 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c @@ -64,8 +64,12 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, u32 data; u32 *cfgaddr; + where &= ~3; + if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) + return 0xffffffff; + cfgaddr = (u32 *)(pci_config_base + - pci_cfg_addr(bus->number, devfn, where & ~3)); + pci_cfg_addr(bus->number, devfn, where)); data = *cfgaddr; return data; } -- cgit v1.2.3-59-g8ed1b From 5a4cbe381122e41749cadf24d59cd63ed84f41c0 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:11:59 +0000 Subject: MIPS: Netlogic: No hazards needed for XLR/XLS TLB and COP0 hazards are handled in hardware for Netlogic XLR/XLS SoCs. Update hazards.h to pick more optimal set of definitions when compiling for XLR/XLS. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4788/ Signed-off-by: John Crispin --- arch/mips/include/asm/hazards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index f0324e92d089..9c309ae4a00e 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -141,7 +141,7 @@ do { \ #elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ - defined(CONFIG_CPU_R5500) + defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) /* * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer. -- cgit v1.2.3-59-g8ed1b From 37a7059bc4228613867645be50120aff17a162a1 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:12:00 +0000 Subject: MIPS: Netlogic: use preset loops per jiffy Doing calibrate delay on a hardware thread will be inaccurate since it depends on the load on other threads in the core. It will also slow down the boot process when done for 128 hardware threads. Switch to a pre-computed loops per jiffy based on the core frequency. The value is computed based on the core frequency and roughly matches the value calculated by calibrate_delay(). Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4791/ Signed-off-by: John Crispin --- arch/mips/netlogic/common/time.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index 20f89bc0507f..5c56555380bb 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -98,6 +98,10 @@ void __init plat_time_init(void) { nlm_init_pic_timer(); mips_hpt_frequency = nlm_get_cpu_frequency(); + if (current_cpu_type() == CPU_XLR) + preset_lpj = mips_hpt_frequency / (3 * HZ); + else + preset_lpj = mips_hpt_frequency / (2 * HZ); pr_info("MIPS counter frequency [%ld]\n", (unsigned long)mips_hpt_frequency); } -- cgit v1.2.3-59-g8ed1b From cba3b643039b9d38284a5fd5143558622b9b64d9 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 14 Jan 2013 15:12:01 +0000 Subject: MIPS: Netlogic: Fix for quad-XLP boot On multi-chip boards, the first core on slave SoCs may take much more time to wakeup. Add code to wait for the core to come up before proceeding with the rest of the boot up. Update xlp_wakeup_core to also skip the boot node and the boot CPU initialization which is already complete. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4783/ Signed-off-by: John Crispin --- arch/mips/netlogic/xlp/wakeup.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c index cb9010642ac3..abb3e08cc052 100644 --- a/arch/mips/netlogic/xlp/wakeup.c +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -51,7 +51,7 @@ #include #include -static int xlp_wakeup_core(uint64_t sysbase, int core) +static int xlp_wakeup_core(uint64_t sysbase, int node, int core) { uint32_t coremask, value; int count; @@ -82,36 +82,51 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) struct nlm_soc_info *nodep; uint64_t syspcibase; uint32_t syscoremask; - int core, n, cpu; + int core, n, cpu, count, val; for (n = 0; n < NLM_NR_NODES; n++) { syspcibase = nlm_get_sys_pcibase(n); if (nlm_read_reg(syspcibase, 0) == 0xffffffff) break; - /* read cores in reset from SYS and account for boot cpu */ - nlm_node_init(n); + /* read cores in reset from SYS */ + if (n != 0) + nlm_node_init(n); nodep = nlm_get_node(n); syscoremask = nlm_read_sys_reg(nodep->sysbase, SYS_CPU_RESET); - if (n == 0) + /* The boot cpu */ + if (n == 0) { syscoremask |= 1; + nodep->coremask = 1; + } for (core = 0; core < NLM_CORES_PER_NODE; core++) { + /* we will be on node 0 core 0 */ + if (n == 0 && core == 0) + continue; + /* see if the core exists */ if ((syscoremask & (1 << core)) == 0) continue; - /* see if at least the first thread is enabled */ + /* see if at least the first hw thread is enabled */ cpu = (n * NLM_CORES_PER_NODE + core) * NLM_THREADS_PER_CORE; if (!cpumask_test_cpu(cpu, wakeup_mask)) continue; /* wake up the core */ - if (xlp_wakeup_core(nodep->sysbase, core)) - nodep->coremask |= 1u << core; - else - pr_err("Failed to enable core %d\n", core); + if (!xlp_wakeup_core(nodep->sysbase, n, core)) + continue; + + /* core is up */ + nodep->coremask |= 1u << core; + + /* spin until the first hw thread sets its ready */ + count = 0x20000000; + do { + val = *(volatile int *)&nlm_cpu_ready[cpu]; + } while (val == 0 && --count > 0); } } } -- cgit v1.2.3-59-g8ed1b From 7b53eb4d40d702a7458588dcfcddaf4498dbbb36 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 16 Jan 2013 11:12:41 +0000 Subject: MIPS: PCI: Multi-node PCI support for Netlogic XLP On a multi-chip XLP board, each node can have 4 PCIe links. Update XLP PCI code to initialize PCIe on all the nodes. Signed-off-by: Jayachandran C Patchwork: http://patchwork.linux-mips.org/patch/4803/ Signed-off-by: John Crispin --- arch/mips/pci/pci-xlp.c | 109 +++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index fbf001a068a4..dd2d3eb3ad31 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -161,32 +162,38 @@ struct pci_controller nlm_pci_controller = { .io_offset = 0x00000000UL, }; -static int get_irq_vector(const struct pci_dev *dev) +static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) { - /* - * For XLP PCIe, there is an IRQ per Link, find out which - * link the device is on to assign interrupts - */ - if (dev->bus->self == NULL) - return 0; + struct pci_bus *bus, *p; - switch (dev->bus->self->devfn) { - case 0x8: - return PIC_PCIE_LINK_0_IRQ; - case 0x9: - return PIC_PCIE_LINK_1_IRQ; - case 0xa: - return PIC_PCIE_LINK_2_IRQ; - case 0xb: - return PIC_PCIE_LINK_3_IRQ; - } - WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); - return 0; + /* Find the bridge on bus 0 */ + bus = dev->bus; + for (p = bus->parent; p && p->number != 0; p = p->parent) + bus = p; + + return p ? bus->self : NULL; +} + +static inline int nlm_pci_link_to_irq(int link) +{ + return PIC_PCIE_LINK_0_IRQ + link; } int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { - return get_irq_vector(dev); + struct pci_dev *lnkdev; + int lnkslot, lnkfunc; + + /* + * For XLP PCIe, there is an IRQ per Link, find out which + * link the device is on to assign interrupts + */ + lnkdev = xlp_get_pcie_link(dev); + if (lnkdev == NULL) + return 0; + lnkfunc = PCI_FUNC(lnkdev->devfn); + lnkslot = PCI_SLOT(lnkdev->devfn); + return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc)); } /* Do platform specific device initialization at pci_enable_device() time */ @@ -201,45 +208,42 @@ int pcibios_plat_dev_init(struct pci_dev *dev) * readl/writel. */ #ifdef __BIG_ENDIAN -static void xlp_config_pci_bswap(void) +static void xlp_config_pci_bswap(int node, int link) { - uint64_t pciebase, sysbase; - int node, i; + uint64_t nbubase, lnkbase; u32 reg; - /* Chip-0 so node set to 0 */ - node = 0; - sysbase = nlm_get_bridge_regbase(node); + nbubase = nlm_get_bridge_regbase(node); + lnkbase = nlm_get_pcie_base(node, link); + /* * Enable byte swap in hardware. Program each link's PCIe SWAP regions * from the link's address ranges. */ - for (i = 0; i < 4; i++) { - pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i)); - if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) - continue; + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); - reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i); - nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg); + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); - reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i); - nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM, - reg | 0xfff); + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); - reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i); - nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg); - - reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i); - nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); - } + reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); + nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); } #else /* Swap configuration not needed in little-endian mode */ -static inline void xlp_config_pci_bswap(void) {} +static inline void xlp_config_pci_bswap(int node, int link) {} #endif /* __BIG_ENDIAN */ static int __init pcibios_init(void) { + struct nlm_soc_info *nodep; + uint64_t pciebase; + int link, n; + u32 reg; + /* Firmware assigns PCI resources */ pci_set_flags(PCI_PROBE_ONLY); pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20); @@ -248,7 +252,26 @@ static int __init pcibios_init(void) ioport_resource.start = 0; ioport_resource.end = ~0; - xlp_config_pci_bswap(); + for (n = 0; n < NLM_NR_NODES; n++) { + nodep = nlm_get_node(n); + if (!nodep->coremask) + continue; /* node does not exist */ + + for (link = 0; link < 4; link++) { + pciebase = nlm_get_pcie_base(n, link); + if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) + continue; + xlp_config_pci_bswap(n, link); + + /* put in intpin and irq - u-boot does not */ + reg = nlm_read_pci_reg(pciebase, 0xf); + reg &= ~0x1fu; + reg |= (1 << 8) | nlm_pci_link_to_irq(link); + nlm_write_pci_reg(pciebase, 0xf, reg); + pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); + } + } + set_io_port_base(CKSEG1); nlm_pci_controller.io_map_base = CKSEG1; -- cgit v1.2.3-59-g8ed1b From 127993e561846e889004d7d21a84fb5a6c40b9c3 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 7 Dec 2012 04:15:03 +0000 Subject: MIPS: Clean-ups for MIPS Technologies Inc. generic header file. Clean up standard header text and remove unused #define. Signed-off-by: Steven J. Hill Patchwork: http://patchwork.linux-mips.org/patch/4703/ Signed-off-by: John Crispin --- arch/mips/include/asm/mips-boards/generic.h | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/arch/mips/include/asm/mips-boards/generic.h b/arch/mips/include/asm/mips-boards/generic.h index 6e23ceb0ba8c..fa188ff08e5a 100644 --- a/arch/mips/include/asm/mips-boards/generic.h +++ b/arch/mips/include/asm/mips-boards/generic.h @@ -1,21 +1,14 @@ /* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive * for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * * Defines of the MIPS boards specific address-MAP, registers, etc. + * + * Copyright (C) 2000,2012 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard + * Steven J. Hill */ #ifndef __ASM_MIPS_BOARDS_GENERIC_H #define __ASM_MIPS_BOARDS_GENERIC_H @@ -30,13 +23,6 @@ #define ASCII_DISPLAY_WORD_BASE 0x1f000410 #define ASCII_DISPLAY_POS_BASE 0x1f000418 - -/* - * Yamon Prom print address. - */ -#define YAMON_PROM_PRINT_ADDR 0x1fc00504 - - /* * Reset register. */ -- cgit v1.2.3-59-g8ed1b From f8fa4811dbb264aef13f982e963389fd828b1ac0 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 7 Dec 2012 03:51:35 +0000 Subject: MIPS: Add support for the M14KEc core. Signed-off-by: Steven J. Hill Patchwork: http://patchwork.linux-mips.org/patch/4682/ Signed-off-by: John Crispin --- arch/mips/include/asm/cpu-features.h | 3 +++ arch/mips/include/asm/cpu.h | 3 +++ arch/mips/include/asm/mipsregs.h | 1 + arch/mips/kernel/cpu-probe.c | 7 +++++++ arch/mips/kernel/proc.c | 1 + arch/mips/mm/c-r4k.c | 1 + arch/mips/mm/tlbex.c | 1 + arch/mips/oprofile/common.c | 1 + arch/mips/oprofile/op_model_mipsxx.c | 4 ++++ 9 files changed, 22 insertions(+) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index c507b931b484..00171cddb6d5 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -98,6 +98,9 @@ #ifndef cpu_has_rixi #define cpu_has_rixi (cpu_data[0].options & MIPS_CPU_RIXI) #endif +#ifndef cpu_has_mmips +#define cpu_has_mmips (cpu_data[0].options & MIPS_CPU_MICROMIPS) +#endif #ifndef cpu_has_vtag_icache #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) #endif diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 90112adb1940..2de2fee16cc4 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -96,6 +96,7 @@ #define PRID_IMP_1004K 0x9900 #define PRID_IMP_1074K 0x9a00 #define PRID_IMP_M14KC 0x9c00 +#define PRID_IMP_M14KEC 0x9e00 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -264,6 +265,7 @@ enum cpu_type_enum { CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, + CPU_M14KEC, /* * MIPS64 class processors @@ -322,6 +324,7 @@ enum cpu_type_enum { #define MIPS_CPU_ULRI 0x00200000 /* CPU has ULRI feature */ #define MIPS_CPU_PCI 0x00400000 /* CPU has Perf Ctr Int indicator */ #define MIPS_CPU_RIXI 0x00800000 /* CPU has TLB Read/eXec Inhibit */ +#define MIPS_CPU_MICROMIPS 0x01000000 /* CPU has microMIPS capability */ /* * CPU ASE encodings diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 7e4e6f8fab37..3e36745670b2 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -595,6 +595,7 @@ #define MIPS_CONF3_DSP2P (_ULCAST_(1) << 11) #define MIPS_CONF3_RXI (_ULCAST_(1) << 12) #define MIPS_CONF3_ULRI (_ULCAST_(1) << 13) +#define MIPS_CONF3_ISA (_ULCAST_(3) << 14) #define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0) #define MIPS_CONF4_MMUEXTDEF (_ULCAST_(3) << 14) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 9f31334ed1de..ba169022fe1d 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -201,6 +201,7 @@ void __init check_wait(void) break; case CPU_M14KC: + case CPU_M14KEC: case CPU_24K: case CPU_34K: case CPU_1004K: @@ -439,6 +440,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->ases |= MIPS_ASE_MIPSMT; if (config3 & MIPS_CONF3_ULRI) c->options |= MIPS_CPU_ULRI; + if (config3 & MIPS_CONF3_ISA) + c->options |= MIPS_CPU_MICROMIPS; return config3 & MIPS_CONF_M; } @@ -861,6 +864,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_M14KC; __cpu_name[cpu] = "MIPS M14Kc"; break; + case PRID_IMP_M14KEC: + c->cputype = CPU_M14KEC; + __cpu_name[cpu] = "MIPS M14KEc"; + break; case PRID_IMP_1004K: c->cputype = CPU_1004K; __cpu_name[cpu] = "MIPS 1004Kc"; diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 07dff54f2ce8..239ae03f3330 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -73,6 +73,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_dsp) seq_printf(m, "%s", " dsp"); if (cpu_has_dsp2) seq_printf(m, "%s", " dsp2"); if (cpu_has_mipsmt) seq_printf(m, "%s", " mt"); + if (cpu_has_mmips) seq_printf(m, "%s", " micromips"); seq_printf(m, "\n"); seq_printf(m, "shadow register sets\t: %d\n", diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 0f7d788e8810..606e8286970c 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1057,6 +1057,7 @@ static void __cpuinit probe_pcache(void) break; case CPU_M14KC: + case CPU_M14KEC: case CPU_24K: case CPU_34K: case CPU_74K: diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 1c8ac49ec72c..074d6595e7b3 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -581,6 +581,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, case CPU_4KC: case CPU_4KEC: case CPU_M14KC: + case CPU_M14KEC: case CPU_SB1: case CPU_SB1A: case CPU_4KSC: diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index e32db1ff02c7..fc41aa997f1a 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -78,6 +78,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) switch (current_cpu_type()) { case CPU_5KC: case CPU_M14KC: + case CPU_M14KEC: case CPU_20KC: case CPU_24K: case CPU_25KF: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 786254630403..18c3afefa67d 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -351,6 +351,10 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/M14Kc"; break; + case CPU_M14KEC: + op_model_mipsxx_ops.cpu_type = "mips/M14KEc"; + break; + case CPU_20KC: op_model_mipsxx_ops.cpu_type = "mips/20K"; break; -- cgit v1.2.3-59-g8ed1b From 32a7ede673cd0be580f24d855099a8a5f195e80c Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Thu, 3 Jan 2013 19:01:52 +0000 Subject: MIPS: dsp: Add assembler support for DSP ASEs. Newer toolchains support the DSP and DSP Rev2 instructions. This patch performs a check for that support and adds compiler and assembler flags for only the files that need use those instructions. Signed-off-by: Steven J. Hill Acked-by: Florian Fainelli Patchwork: http://patchwork.linux-mips.org/patch/4752/ Signed-off-by: John Crispin --- arch/mips/include/asm/mipsregs.h | 53 +++++++++++++++++++++++++++------------- arch/mips/kernel/Makefile | 31 +++++++++++++++++++++++ 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3e36745670b2..578132219ff6 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1155,36 +1155,26 @@ do { \ : "=r" (__res)); \ __res;}) +#ifdef HAVE_AS_DSP #define rddsp(mask) \ ({ \ - unsigned int __res; \ + unsigned int __dspctl; \ \ __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # rddsp $1, %x1 \n" \ - " .word 0x7c000cb8 | (%x1 << 16) \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__res) \ + " rddsp %0, %x1 \n" \ + : "=r" (__dspctl) \ : "i" (mask)); \ - __res; \ + __dspctl; \ }) #define wrdsp(val, mask) \ do { \ __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # wrdsp $1, %x1 \n" \ - " .word 0x7c2004f8 | (%x1 << 11) \n" \ - " .set pop \n" \ - : \ + " wrdsp %0, %x1 \n" \ + : \ : "r" (val), "i" (mask)); \ } while (0) -#if 0 /* Need DSP ASE capable assembler ... */ #define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;}) #define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;}) #define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;}) @@ -1207,6 +1197,35 @@ do { \ #else +#define rddsp(mask) \ +({ \ + unsigned int __res; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # rddsp $1, %x1 \n" \ + " .word 0x7c000cb8 | (%x1 << 16) \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__res) \ + : "i" (mask)); \ + __res; \ +}) + +#define wrdsp(val, mask) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # wrdsp $1, %x1 \n" \ + " .word 0x7c2004f8 | (%x1 << 11) \n" \ + " .set pop \n" \ + : \ + : "r" (val), "i" (mask)); \ +} while (0) + #define mfhi0() \ ({ \ unsigned long __treg; \ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 007c33d73715..6c17e1f3d0ec 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -98,4 +98,35 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +# +# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe +# to enable DSP assembler support here even if the MIPS Release 2 CPU we +# are targetting does not support DSP because all code-paths making use of +# it properly check that the running CPU *actually does* support these +# instructions. +# +ifeq ($(CONFIG_CPU_MIPSR2), y) +CFLAGS_DSP = -DHAVE_AS_DSP + +# +# Check if assembler supports DSP ASE +# +ifeq ($(call cc-option-yn,-mdsp), y) +CFLAGS_DSP += -mdsp +endif + +# +# Check if assembler supports DSP ASE Rev2 +# +ifeq ($(call cc-option-yn,-mdspr2), y) +CFLAGS_DSP += -mdspr2 +endif + +CFLAGS_signal.o = $(CFLAGS_DSP) +CFLAGS_signal32.o = $(CFLAGS_DSP) +CFLAGS_process.o = $(CFLAGS_DSP) +CFLAGS_branch.o = $(CFLAGS_DSP) +CFLAGS_ptrace.o = $(CFLAGS_DSP) +endif + CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) -- cgit v1.2.3-59-g8ed1b From d0c1b478e0b2f0bcbb2a58db6bc5e13354068064 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 7 Dec 2012 03:53:29 +0000 Subject: MIPS: dsp: Support toolchains without DSP ASE and microMIPS. Add macros to support the DSP ASE with microMIPS kernels when the toolchain does not have support. Signed-off-by: Steven J. Hill Patchwork: http://patchwork.linux-mips.org/patch/4686/ Signed-off-by: John Crispin --- arch/mips/include/asm/mipsregs.h | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 578132219ff6..24417de673c5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1197,6 +1197,94 @@ do { \ #else +#ifdef CONFIG_CPU_MICROMIPS +#define rddsp(mask) \ +({ \ + unsigned int __res; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " # rddsp $1, %x1 \n" \ + " .hword ((0x0020067c | (%x1 << 14)) >> 16) \n" \ + " .hword ((0x0020067c | (%x1 << 14)) & 0xffff) \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__res) \ + : "i" (mask)); \ + __res; \ +}) + +#define wrdsp(val, mask) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " # wrdsp $1, %x1 \n" \ + " .hword ((0x0020167c | (%x1 << 14)) >> 16) \n" \ + " .hword ((0x0020167c | (%x1 << 14)) & 0xffff) \n" \ + " .set pop \n" \ + : \ + : "r" (val), "i" (mask)); \ +} while (0) + +#define _umips_dsp_mfxxx(ins) \ +({ \ + unsigned long __treg; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .hword 0x0001 \n" \ + " .hword %x1 \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__treg) \ + : "i" (ins)); \ + __treg; \ +}) + +#define _umips_dsp_mtxxx(val, ins) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " move $1, %0 \n" \ + " .hword 0x0001 \n" \ + " .hword %x1 \n" \ + " .set pop \n" \ + : \ + : "r" (val), "i" (ins)); \ +} while (0) + +#define _umips_dsp_mflo(reg) _umips_dsp_mfxxx((reg << 14) | 0x107c) +#define _umips_dsp_mfhi(reg) _umips_dsp_mfxxx((reg << 14) | 0x007c) + +#define _umips_dsp_mtlo(val, reg) _umips_dsp_mtxxx(val, ((reg << 14) | 0x307c)) +#define _umips_dsp_mthi(val, reg) _umips_dsp_mtxxx(val, ((reg << 14) | 0x207c)) + +#define mflo0() _umips_dsp_mflo(0) +#define mflo1() _umips_dsp_mflo(1) +#define mflo2() _umips_dsp_mflo(2) +#define mflo3() _umips_dsp_mflo(3) + +#define mfhi0() _umips_dsp_mfhi(0) +#define mfhi1() _umips_dsp_mfhi(1) +#define mfhi2() _umips_dsp_mfhi(2) +#define mfhi3() _umips_dsp_mfhi(3) + +#define mtlo0(x) _umips_dsp_mtlo(x, 0) +#define mtlo1(x) _umips_dsp_mtlo(x, 1) +#define mtlo2(x) _umips_dsp_mtlo(x, 2) +#define mtlo3(x) _umips_dsp_mtlo(x, 3) + +#define mthi0(x) _umips_dsp_mthi(x, 0) +#define mthi1(x) _umips_dsp_mthi(x, 1) +#define mthi2(x) _umips_dsp_mthi(x, 2) +#define mthi3(x) _umips_dsp_mthi(x, 3) + +#else /* !CONFIG_CPU_MICROMIPS */ #define rddsp(mask) \ ({ \ unsigned int __res; \ @@ -1450,6 +1538,7 @@ do { \ : "r" (x)); \ } while (0) +#endif /* CONFIG_CPU_MICROMIPS */ #endif /* -- cgit v1.2.3-59-g8ed1b From 4cb764b4541fe9eacc237b6851198a4c8497b9c4 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 7 Dec 2012 03:53:52 +0000 Subject: MIPS: dsp: Simplify the DSP macros. Simplify the DSP macros for vanilla (non-microMIPS) kernels and toolchains that do not support the DSP ASEs. Signed-off-by: Steven J. Hill Patchwork: http://patchwork.linux-mips.org/patch/4687/ Signed-off-by: John Crispin --- arch/mips/include/asm/mipsregs.h | 231 +++++---------------------------------- 1 file changed, 30 insertions(+), 201 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 24417de673c5..9f47cda632ab 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1314,229 +1314,58 @@ do { \ : "r" (val), "i" (mask)); \ } while (0) -#define mfhi0() \ +#define _dsp_mfxxx(ins) \ ({ \ unsigned long __treg; \ \ __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mfhi %0, $ac0 \n" \ - " .word 0x00000810 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mfhi1() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mfhi %0, $ac1 \n" \ - " .word 0x00200810 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mfhi2() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mfhi %0, $ac2 \n" \ - " .word 0x00400810 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mfhi3() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mfhi %0, $ac3 \n" \ - " .word 0x00600810 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mflo0() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mflo %0, $ac0 \n" \ - " .word 0x00000812 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mflo1() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mflo %0, $ac1 \n" \ - " .word 0x00200812 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mflo2() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mflo %0, $ac2 \n" \ - " .word 0x00400812 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mflo3() \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # mflo %0, $ac3 \n" \ - " .word 0x00600812 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg)); \ - __treg; \ -}) - -#define mthi0(x) \ -do { \ - __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ - " move $1, %0 \n" \ - " # mthi $1, $ac0 \n" \ - " .word 0x00200011 \n" \ + " .word (0x00000810 | %1) \n" \ + " move %0, $1 \n" \ " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) + : "=r" (__treg) \ + : "i" (ins)); \ + __treg; \ +}) -#define mthi1(x) \ +#define _dsp_mtxxx(val, ins) \ do { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ " move $1, %0 \n" \ - " # mthi $1, $ac1 \n" \ - " .word 0x00200811 \n" \ + " .word (0x00200011 | %1) \n" \ " .set pop \n" \ : \ - : "r" (x)); \ + : "r" (val), "i" (ins)); \ } while (0) -#define mthi2(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mthi $1, $ac2 \n" \ - " .word 0x00201011 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define _dsp_mflo(reg) _dsp_mfxxx((reg << 21) | 0x0002) +#define _dsp_mfhi(reg) _dsp_mfxxx((reg << 21) | 0x0000) -#define mthi3(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mthi $1, $ac3 \n" \ - " .word 0x00201811 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define _dsp_mtlo(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0002)) +#define _dsp_mthi(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0000)) -#define mtlo0(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mtlo $1, $ac0 \n" \ - " .word 0x00200013 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define mflo0() _dsp_mflo(0) +#define mflo1() _dsp_mflo(1) +#define mflo2() _dsp_mflo(2) +#define mflo3() _dsp_mflo(3) -#define mtlo1(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mtlo $1, $ac1 \n" \ - " .word 0x00200813 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define mfhi0() _dsp_mfhi(0) +#define mfhi1() _dsp_mfhi(1) +#define mfhi2() _dsp_mfhi(2) +#define mfhi3() _dsp_mfhi(3) -#define mtlo2(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mtlo $1, $ac2 \n" \ - " .word 0x00201013 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define mtlo0(x) _dsp_mtlo(x, 0) +#define mtlo1(x) _dsp_mtlo(x, 1) +#define mtlo2(x) _dsp_mtlo(x, 2) +#define mtlo3(x) _dsp_mtlo(x, 3) -#define mtlo3(x) \ -do { \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # mtlo $1, $ac3 \n" \ - " .word 0x00201813 \n" \ - " .set pop \n" \ - : \ - : "r" (x)); \ -} while (0) +#define mthi0(x) _dsp_mthi(x, 0) +#define mthi1(x) _dsp_mthi(x, 1) +#define mthi2(x) _dsp_mthi(x, 2) +#define mthi3(x) _dsp_mthi(x, 3) #endif /* CONFIG_CPU_MICROMIPS */ #endif -- cgit v1.2.3-59-g8ed1b From 778eeb1b199b85bec79b49ac483b013e270636ea Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Fri, 7 Dec 2012 03:51:04 +0000 Subject: MIPS: Add new GIC clocksource. Add new clocksource that uses the counter present on the MIPS Global Interrupt Controller. Signed-off-by: Steven J. Hill Patchwork: http://patchwork.linux-mips.org/patch/4681/ Signed-off-by: John Crispin --- arch/mips/Kconfig | 4 ++ arch/mips/include/asm/gic.h | 1 + arch/mips/include/asm/time.h | 2 +- arch/mips/kernel/Makefile | 1 + arch/mips/kernel/csrc-gic.c | 49 ++++++++++++++++++++++++ arch/mips/mti-malta/malta-time.c | 83 ++++++++++++++++++++++++---------------- 6 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 arch/mips/kernel/csrc-gic.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index daeafe26cfb2..8f8666c8f28d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -296,6 +296,7 @@ config MIPS_MALTA select BOOT_RAW select CEVT_R4K select CSRC_R4K + select CSRC_GIC select DMA_NONCOHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM @@ -928,6 +929,9 @@ config CSRC_POWERTV config CSRC_R4K bool +config CSRC_GIC + bool + config CSRC_SB1250 bool diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 37620db588be..bbddd257c243 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -359,6 +359,7 @@ struct gic_shared_intr_map { /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ #define GIC_PIN_TO_VEC_OFFSET (1) +extern int gic_present; extern unsigned long _gic_base; extern unsigned int gic_irq_base; extern unsigned int gic_irq_flags[]; diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index 761f2e92119e..d77a535d83eb 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -75,7 +75,7 @@ extern int init_r4k_clocksource(void); static inline int init_mips_clocksource(void) { -#ifdef CONFIG_CSRC_R4K +#if defined(CONFIG_CSRC_R4K) && !defined(CONFIG_CSRC_GIC) return init_r4k_clocksource(); #else return 0; diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 6c17e1f3d0ec..f416de34c9eb 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o +obj-$(CONFIG_CSRC_GIC) += csrc-gic.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/mips/kernel/csrc-gic.c b/arch/mips/kernel/csrc-gic.c new file mode 100644 index 000000000000..5dca24bce51b --- /dev/null +++ b/arch/mips/kernel/csrc-gic.c @@ -0,0 +1,49 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include +#include + +#include +#include + +static cycle_t gic_hpt_read(struct clocksource *cs) +{ + unsigned int hi, hi2, lo; + + do { + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); + } while (hi2 != hi); + + return (((cycle_t) hi) << 32) + lo; +} + +static struct clocksource gic_clocksource = { + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init gic_clocksource_init(unsigned int frequency) +{ + unsigned int config, bits; + + /* Calculate the clocksource mask. */ + GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), config); + bits = 32 + ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >> + (GIC_SH_CONFIG_COUNTBITS_SHF - 2)); + + /* Set clocksource mask. */ + gic_clocksource.mask = CLOCKSOURCE_MASK(bits); + + /* Calculate a somewhat reasonable rating value. */ + gic_clocksource.rating = 200 + frequency / 10000000; + + clocksource_register_hz(&gic_clocksource, frequency); +} diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 115f5bc06003..a144b89cf9ba 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -17,7 +17,6 @@ * * Setting up the clock on the MIPS boards. */ - #include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include #include @@ -34,11 +32,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -46,6 +44,7 @@ #include unsigned long cpu_khz; +int gic_frequency; static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; @@ -61,44 +60,50 @@ static void mips_perf_dispatch(void) do_IRQ(mips_cpu_perf_irq); } +static unsigned int freqround(unsigned int freq, unsigned int amount) +{ + freq += amount; + freq -= freq % (amount*2); + return freq; +} + /* - * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect + * Estimate CPU and GIC frequencies. */ -static unsigned int __init estimate_cpu_frequency(void) +static void __init estimate_frequencies(void) { - unsigned int prid = read_c0_prid() & 0xffff00; - unsigned int count; - unsigned long flags; - unsigned int start; + unsigned int count, start; + unsigned int giccount = 0, gicstart = 0; local_irq_save(flags); - /* Start counter exactly on falling edge of update flag */ + /* Start counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - /* Start r4k counter. */ + /* Initialize counters. */ start = read_c0_count(); + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); - /* Read counter exactly on falling edge of update flag */ + /* Read counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - count = read_c0_count() - start; + count = read_c0_count(); + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); - /* restore interrupts */ local_irq_restore(flags); - mips_hpt_frequency = count; - if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && - (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) - count *= 2; - - count += 5000; /* round */ - count -= count%10000; + count -= start; + if (gic_present) + giccount -= gicstart; - return count; + mips_hpt_frequency = count; + if (gic_present) + gic_frequency = giccount; } void read_persistent_clock(struct timespec *ts) @@ -144,22 +149,34 @@ unsigned int __cpuinit get_c0_compare_int(void) void __init plat_time_init(void) { - unsigned int est_freq; - - /* Set Data mode - binary. */ - CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); - - est_freq = estimate_cpu_frequency(); + unsigned int prid = read_c0_prid() & 0xffff00; + unsigned int freq; - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); + estimate_frequencies(); - cpu_khz = est_freq / 1000; + freq = mips_hpt_frequency; + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + freq = freqround(freq, 5000); + pr_debug("CPU frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); + cpu_khz = freq / 1000; + + if (gic_present) { + freq = freqround(gic_frequency, 5000); + pr_debug("GIC frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); + gic_clocksource_init(gic_frequency); + } else + init_r4k_clocksource(); - mips_scroll_message(); -#ifdef CONFIG_I8253 /* Only Malta has a PIT */ +#ifdef CONFIG_I8253 + /* Only Malta has a PIT. */ setup_pit_timer(); #endif + mips_scroll_message(); + plat_perf_setup(); } -- cgit v1.2.3-59-g8ed1b From 8838becdf5f7261d7f5dfbbe957fe9b9ed188aec Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 29 Jan 2013 08:19:12 +0000 Subject: MIPS: ath79: fix GPIO function selection for AR934x SoCs GPIO function selection is not working on the AR934x SoCs because the offset of the function selection register is different on those. Add a helper routine which returns the correct register address based on the SoC type, and use that in the 'ath79_gpio_function_*' routines. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4870/ Signed-off-by: John Crispin --- arch/mips/ath79/gpio.c | 38 ++++++++++++++++++-------- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 2 ++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index 48fe762d2526..662a10ecd8e7 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -137,47 +137,61 @@ static struct gpio_chip ath79_gpio_chip = { .base = 0, }; +static void __iomem *ath79_gpio_get_function_reg(void) +{ + u32 reg = 0; + + if (soc_is_ar71xx() || + soc_is_ar724x() || + soc_is_ar913x() || + soc_is_ar933x()) + reg = AR71XX_GPIO_REG_FUNC; + else if (soc_is_ar934x()) + reg = AR934X_GPIO_REG_FUNC; + else + BUG(); + + return ath79_gpio_base + reg; +} + void ath79_gpio_function_enable(u32 mask) { - void __iomem *base = ath79_gpio_base; + void __iomem *reg = ath79_gpio_get_function_reg(); unsigned long flags; spin_lock_irqsave(&ath79_gpio_lock, flags); - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask, - base + AR71XX_GPIO_REG_FUNC); + __raw_writel(__raw_readl(reg) | mask, reg); /* flush write */ - __raw_readl(base + AR71XX_GPIO_REG_FUNC); + __raw_readl(reg); spin_unlock_irqrestore(&ath79_gpio_lock, flags); } void ath79_gpio_function_disable(u32 mask) { - void __iomem *base = ath79_gpio_base; + void __iomem *reg = ath79_gpio_get_function_reg(); unsigned long flags; spin_lock_irqsave(&ath79_gpio_lock, flags); - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask, - base + AR71XX_GPIO_REG_FUNC); + __raw_writel(__raw_readl(reg) & ~mask, reg); /* flush write */ - __raw_readl(base + AR71XX_GPIO_REG_FUNC); + __raw_readl(reg); spin_unlock_irqrestore(&ath79_gpio_lock, flags); } void ath79_gpio_function_setup(u32 set, u32 clear) { - void __iomem *base = ath79_gpio_base; + void __iomem *reg = ath79_gpio_get_function_reg(); unsigned long flags; spin_lock_irqsave(&ath79_gpio_lock, flags); - __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set, - base + AR71XX_GPIO_REG_FUNC); + __raw_writel((__raw_readl(reg) & ~clear) | set, reg); /* flush write */ - __raw_readl(base + AR71XX_GPIO_REG_FUNC); + __raw_readl(reg); spin_unlock_irqrestore(&ath79_gpio_lock, flags); } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index a5e0f17ea77c..7d44b5d5f609 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -401,6 +401,8 @@ #define AR71XX_GPIO_REG_INT_ENABLE 0x24 #define AR71XX_GPIO_REG_FUNC 0x28 +#define AR934X_GPIO_REG_FUNC 0x6c + #define AR71XX_GPIO_COUNT 16 #define AR7240_GPIO_COUNT 18 #define AR7241_GPIO_COUNT 20 -- cgit v1.2.3-59-g8ed1b From f160a289e0e8848391f5ec48ff1a014b9c04b162 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 29 Jan 2013 08:19:13 +0000 Subject: MIPS: ath79: simplify ath79_gpio_function_* routines Make ath79_gpio_function_{en,dis}able to be wrappers around ath79_gpio_function_setup. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4871/ Signed-off-by: John Crispin --- arch/mips/ath79/gpio.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index 662a10ecd8e7..b7ed207e94a1 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -154,46 +154,28 @@ static void __iomem *ath79_gpio_get_function_reg(void) return ath79_gpio_base + reg; } -void ath79_gpio_function_enable(u32 mask) +void ath79_gpio_function_setup(u32 set, u32 clear) { void __iomem *reg = ath79_gpio_get_function_reg(); unsigned long flags; spin_lock_irqsave(&ath79_gpio_lock, flags); - __raw_writel(__raw_readl(reg) | mask, reg); + __raw_writel((__raw_readl(reg) & ~clear) | set, reg); /* flush write */ __raw_readl(reg); spin_unlock_irqrestore(&ath79_gpio_lock, flags); } -void ath79_gpio_function_disable(u32 mask) +void ath79_gpio_function_enable(u32 mask) { - void __iomem *reg = ath79_gpio_get_function_reg(); - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel(__raw_readl(reg) & ~mask, reg); - /* flush write */ - __raw_readl(reg); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); + ath79_gpio_function_setup(mask, 0); } -void ath79_gpio_function_setup(u32 set, u32 clear) +void ath79_gpio_function_disable(u32 mask) { - void __iomem *reg = ath79_gpio_get_function_reg(); - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel((__raw_readl(reg) & ~clear) | set, reg); - /* flush write */ - __raw_readl(reg); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); + ath79_gpio_function_setup(0, mask); } void __init ath79_gpio_init(void) -- cgit v1.2.3-59-g8ed1b From 9c099c4e79b67d5578ce8142e6214950be4fcf43 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 29 Jan 2013 16:13:17 +0000 Subject: MIPS: ath79: simplify MISC IRQ handling The current code uses multiple if statements for demultiplexing the different interrupt sources. Additionally, the MISC interrupt controller has 32 interrupt sources and the current code does not handles all of them. Get rid of the if statements and process all interrupt sources in a loop to fix these issues. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4874/ Signed-off-by: John Crispin --- arch/mips/ath79/irq.c | 45 +++++++--------------------------- arch/mips/include/asm/mach-ath79/irq.h | 1 + 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 90d09fc15398..219cfa1f5961 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -35,44 +35,17 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); - if (pending & MISC_INT_UART) - generic_handle_irq(ATH79_MISC_IRQ_UART); - - else if (pending & MISC_INT_DMA) - generic_handle_irq(ATH79_MISC_IRQ_DMA); - - else if (pending & MISC_INT_PERFC) - generic_handle_irq(ATH79_MISC_IRQ_PERFC); - - else if (pending & MISC_INT_TIMER) - generic_handle_irq(ATH79_MISC_IRQ_TIMER); - - else if (pending & MISC_INT_TIMER2) - generic_handle_irq(ATH79_MISC_IRQ_TIMER2); - - else if (pending & MISC_INT_TIMER3) - generic_handle_irq(ATH79_MISC_IRQ_TIMER3); - - else if (pending & MISC_INT_TIMER4) - generic_handle_irq(ATH79_MISC_IRQ_TIMER4); - - else if (pending & MISC_INT_OHCI) - generic_handle_irq(ATH79_MISC_IRQ_OHCI); - - else if (pending & MISC_INT_ERROR) - generic_handle_irq(ATH79_MISC_IRQ_ERROR); - - else if (pending & MISC_INT_GPIO) - generic_handle_irq(ATH79_MISC_IRQ_GPIO); - - else if (pending & MISC_INT_WDOG) - generic_handle_irq(ATH79_MISC_IRQ_WDOG); + if (!pending) { + spurious_interrupt(); + return; + } - else if (pending & MISC_INT_ETHSW) - generic_handle_irq(ATH79_MISC_IRQ_ETHSW); + while (pending) { + int bit = __ffs(pending); - else - spurious_interrupt(); + generic_handle_irq(ATH79_MISC_IRQ(bit)); + pending &= ~BIT(bit); + } } static void ar71xx_misc_irq_unmask(struct irq_data *d) diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h index 0968f69e2018..158ad7f41313 100644 --- a/arch/mips/include/asm/mach-ath79/irq.h +++ b/arch/mips/include/asm/mach-ath79/irq.h @@ -14,6 +14,7 @@ #define ATH79_MISC_IRQ_BASE 8 #define ATH79_MISC_IRQ_COUNT 32 +#define ATH79_MISC_IRQ(_x) (ATH79_MISC_IRQ_BASE + (_x)) #define ATH79_PCI_IRQ_BASE (ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT) #define ATH79_PCI_IRQ_COUNT 6 -- cgit v1.2.3-59-g8ed1b From 247796175ea5dc7c838e8e76a14795fb09360649 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 20 Jul 2012 18:58:34 +0200 Subject: Document: devicetree: add OF documents for lantiq serial port Signed-off-by: John Crispin Cc: Rob Herring Cc: devicetree-discuss@lists.ozlabs.org --- Documentation/devicetree/bindings/serial/lantiq_asc.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/lantiq_asc.txt diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt new file mode 100644 index 000000000000..5b78591aaa46 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/lantiq_asc.txt @@ -0,0 +1,16 @@ +Lantiq SoC ASC serial controller + +Required properties: +- compatible : Should be "lantiq,asc" +- reg : Address and length of the register set for the device +- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier + depends on the interrupt-parent interrupt controller. + +Example: + +asc1: serial@E100C00 { + compatible = "lantiq,asc"; + reg = <0xE100C00 0x400>; + interrupt-parent = <&icu0>; + interrupts = <112 113 114>; +}; -- cgit v1.2.3-59-g8ed1b From 8563991026ee98bb5e477167236972a45dfea0e3 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 21 Jan 2013 18:25:59 +0100 Subject: MIPS: ralink: adds include files Before we start adding the platform code we add the common include files. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4893/ --- arch/mips/include/asm/mach-ralink/ralink_regs.h | 39 ++++++++++++++++++++++ arch/mips/include/asm/mach-ralink/war.h | 25 ++++++++++++++ arch/mips/ralink/common.h | 44 +++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 arch/mips/include/asm/mach-ralink/ralink_regs.h create mode 100644 arch/mips/include/asm/mach-ralink/war.h create mode 100644 arch/mips/ralink/common.h diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h new file mode 100644 index 000000000000..5a508f9f9432 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h @@ -0,0 +1,39 @@ +/* + * Ralink SoC register definitions + * + * Copyright (C) 2013 John Crispin + * Copyright (C) 2008-2010 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _RALINK_REGS_H_ +#define _RALINK_REGS_H_ + +extern __iomem void *rt_sysc_membase; +extern __iomem void *rt_memc_membase; + +static inline void rt_sysc_w32(u32 val, unsigned reg) +{ + __raw_writel(val, rt_sysc_membase + reg); +} + +static inline u32 rt_sysc_r32(unsigned reg) +{ + return __raw_readl(rt_sysc_membase + reg); +} + +static inline void rt_memc_w32(u32 val, unsigned reg) +{ + __raw_writel(val, rt_memc_membase + reg); +} + +static inline u32 rt_memc_r32(unsigned reg) +{ + return __raw_readl(rt_memc_membase + reg); +} + +#endif /* _RALINK_REGS_H_ */ diff --git a/arch/mips/include/asm/mach-ralink/war.h b/arch/mips/include/asm/mach-ralink/war.h new file mode 100644 index 000000000000..a7b712cf2d28 --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MACH_RALINK_WAR_H +#define __ASM_MACH_RALINK_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MACH_RALINK_WAR_H */ diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h new file mode 100644 index 000000000000..300990313e1b --- /dev/null +++ b/arch/mips/ralink/common.h @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2013 John Crispin + */ + +#ifndef _RALINK_COMMON_H__ +#define _RALINK_COMMON_H__ + +#define RAMIPS_SYS_TYPE_LEN 32 + +struct ralink_pinmux_grp { + const char *name; + u32 mask; + int gpio_first; + int gpio_last; +}; + +struct ralink_pinmux { + struct ralink_pinmux_grp *mode; + struct ralink_pinmux_grp *uart; + int uart_shift; + void (*wdt_reset)(void); +}; +extern struct ralink_pinmux gpio_pinmux; + +struct ralink_soc_info { + unsigned char sys_type[RAMIPS_SYS_TYPE_LEN]; + unsigned char *compatible; +}; +extern struct ralink_soc_info soc_info; + +extern void ralink_of_remap(void); + +extern void ralink_clk_init(void); +extern void ralink_clk_add(const char *dev, unsigned long rate); + +extern void prom_soc_init(struct ralink_soc_info *soc_info); + +__iomem void *plat_of_remap_node(const char *node); + +#endif /* _RALINK_COMMON_H__ */ -- cgit v1.2.3-59-g8ed1b From 19d3814e7b325f8965fd71f329b3467a97f8d217 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:00:50 +0100 Subject: MIPS: ralink: adds irq code All of the Ralink Wifi SoC currently supported by this series share the same interrupt controller (INTC). Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4890/ --- arch/mips/ralink/irq.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 arch/mips/ralink/irq.c diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c new file mode 100644 index 000000000000..e62c9751e2d8 --- /dev/null +++ b/arch/mips/ralink/irq.c @@ -0,0 +1,176 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2009 Gabor Juhos + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +/* INTC register offsets */ +#define INTC_REG_STATUS0 0x00 +#define INTC_REG_STATUS1 0x04 +#define INTC_REG_TYPE 0x20 +#define INTC_REG_RAW_STATUS 0x30 +#define INTC_REG_ENABLE 0x34 +#define INTC_REG_DISABLE 0x38 + +#define INTC_INT_GLOBAL BIT(31) + +#define RALINK_CPU_IRQ_INTC (MIPS_CPU_IRQ_BASE + 2) +#define RALINK_CPU_IRQ_FE (MIPS_CPU_IRQ_BASE + 5) +#define RALINK_CPU_IRQ_WIFI (MIPS_CPU_IRQ_BASE + 6) +#define RALINK_CPU_IRQ_COUNTER (MIPS_CPU_IRQ_BASE + 7) + +/* we have a cascade of 8 irqs */ +#define RALINK_INTC_IRQ_BASE 8 + +/* we have 32 SoC irqs */ +#define RALINK_INTC_IRQ_COUNT 32 + +#define RALINK_INTC_IRQ_PERFC (RALINK_INTC_IRQ_BASE + 9) + +static void __iomem *rt_intc_membase; + +static inline void rt_intc_w32(u32 val, unsigned reg) +{ + __raw_writel(val, rt_intc_membase + reg); +} + +static inline u32 rt_intc_r32(unsigned reg) +{ + return __raw_readl(rt_intc_membase + reg); +} + +static void ralink_intc_irq_unmask(struct irq_data *d) +{ + rt_intc_w32(BIT(d->hwirq), INTC_REG_ENABLE); +} + +static void ralink_intc_irq_mask(struct irq_data *d) +{ + rt_intc_w32(BIT(d->hwirq), INTC_REG_DISABLE); +} + +static struct irq_chip ralink_intc_irq_chip = { + .name = "INTC", + .irq_unmask = ralink_intc_irq_unmask, + .irq_mask = ralink_intc_irq_mask, + .irq_mask_ack = ralink_intc_irq_mask, +}; + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} + +static void ralink_intc_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + u32 pending = rt_intc_r32(INTC_REG_STATUS0); + + if (pending) { + struct irq_domain *domain = irq_get_handler_data(irq); + generic_handle_irq(irq_find_mapping(domain, __ffs(pending))); + } else { + spurious_interrupt(); + } +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned long pending; + + pending = read_c0_status() & read_c0_cause() & ST0_IM; + + if (pending & STATUSF_IP7) + do_IRQ(RALINK_CPU_IRQ_COUNTER); + + else if (pending & STATUSF_IP5) + do_IRQ(RALINK_CPU_IRQ_FE); + + else if (pending & STATUSF_IP6) + do_IRQ(RALINK_CPU_IRQ_WIFI); + + else if (pending & STATUSF_IP2) + do_IRQ(RALINK_CPU_IRQ_INTC); + + else + spurious_interrupt(); +} + +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &ralink_intc_irq_chip, handle_level_irq); + + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = intc_map, +}; + +static int __init intc_of_init(struct device_node *node, + struct device_node *parent) +{ + struct resource res; + struct irq_domain *domain; + + mips_cpu_irq_init(); + + if (of_address_to_resource(node, 0, &res)) + panic("Failed to get intc memory range"); + + if (request_mem_region(res.start, resource_size(&res), + res.name) < 0) + pr_err("Failed to request intc memory"); + + rt_intc_membase = ioremap_nocache(res.start, + resource_size(&res)); + if (!rt_intc_membase) + panic("Failed to remap intc memory"); + + /* disable all interrupts */ + rt_intc_w32(~0, INTC_REG_DISABLE); + + /* route all INTC interrupts to MIPS HW0 interrupt */ + rt_intc_w32(0, INTC_REG_TYPE); + + domain = irq_domain_add_legacy(node, RALINK_INTC_IRQ_COUNT, + RALINK_INTC_IRQ_BASE, 0, &irq_domain_ops, NULL); + if (!domain) + panic("Failed to add irqdomain"); + + rt_intc_w32(INTC_INT_GLOBAL, INTC_REG_ENABLE); + + irq_set_chained_handler(RALINK_CPU_IRQ_INTC, ralink_intc_irq_handler); + irq_set_handler_data(RALINK_CPU_IRQ_INTC, domain); + + cp0_perfcount_irq = irq_create_mapping(domain, 9); + + return 0; +} + +static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + of_irq_init(of_irq_ids); +} + -- cgit v1.2.3-59-g8ed1b From c06e836ada59fbc6d1109277e693e5b3e056ac12 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:00:57 +0100 Subject: MIPS: ralink: adds reset code Resetting these SoCs requires no real magic. The code is straight forward. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4891/ --- arch/mips/ralink/reset.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 arch/mips/ralink/reset.c diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c new file mode 100644 index 000000000000..22120e512e7e --- /dev/null +++ b/arch/mips/ralink/reset.c @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2008-2009 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * Copyright (C) 2013 John Crispin + */ + +#include +#include + +#include + +#include + +/* Reset Control */ +#define SYSC_REG_RESET_CTRL 0x034 +#define RSTCTL_RESET_SYSTEM BIT(0) + +static void ralink_restart(char *command) +{ + local_irq_disable(); + rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL); + unreachable(); +} + +static void ralink_halt(void) +{ + local_irq_disable(); + unreachable(); +} + +static int __init mips_reboot_setup(void) +{ + _machine_restart = ralink_restart; + _machine_halt = ralink_halt; + pm_power_off = ralink_halt; + + return 0; +} + +arch_initcall(mips_reboot_setup); -- cgit v1.2.3-59-g8ed1b From 7e47cefa69c8ed2c889522ce29fcce73ce8cf08e Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:01:05 +0100 Subject: MIPS: ralink: adds prom and cmdline code Add minimal code to handle commandlines. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4892/ --- arch/mips/ralink/prom.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 arch/mips/ralink/prom.c diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c new file mode 100644 index 000000000000..9c64f029d047 --- /dev/null +++ b/arch/mips/ralink/prom.c @@ -0,0 +1,69 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2009 Gabor Juhos + * Copyright (C) 2010 Joonas Lahtinen + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include + +#include +#include + +#include "common.h" + +struct ralink_soc_info soc_info; + +const char *get_system_type(void) +{ + return soc_info.sys_type; +} + +static __init void prom_init_cmdline(int argc, char **argv) +{ + int i; + + pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n", + (unsigned int)fw_arg0, (unsigned int)fw_arg1, + (unsigned int)fw_arg2, (unsigned int)fw_arg3); + + argc = fw_arg0; + argv = (char **) KSEG1ADDR(fw_arg1); + + if (!argv) { + pr_debug("argv=%p is invalid, skipping\n", + argv); + return; + } + + for (i = 0; i < argc; i++) { + char *p = (char *) KSEG1ADDR(argv[i]); + + if (CPHYSADDR(p) && *p) { + pr_debug("argv[%d]: %s\n", i, p); + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); + } + } +} + +void __init prom_init(void) +{ + int argc; + char **argv; + + prom_soc_init(&soc_info); + + pr_info("SoC Type: %s\n", get_system_type()); + + prom_init_cmdline(argc, argv); +} + +void __init prom_free_prom_memory(void) +{ +} -- cgit v1.2.3-59-g8ed1b From 3f0a06b0368d25608841843e9d65a7289ad9f14a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:01:29 +0100 Subject: MIPS: ralink: adds clkdev code These SoCs have a limited number of fixed rate clocks. Add support for the clk and clkdev api. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4894/ --- arch/mips/ralink/clk.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 arch/mips/ralink/clk.c diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c new file mode 100644 index 000000000000..8dfa22ff300b --- /dev/null +++ b/arch/mips/ralink/clk.c @@ -0,0 +1,72 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2011 Gabor Juhos + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "common.h" + +struct clk { + struct clk_lookup cl; + unsigned long rate; +}; + +void ralink_clk_add(const char *dev, unsigned long rate) +{ + struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); + + if (!clk) + panic("failed to add clock\n"); + + clk->cl.dev_id = dev; + clk->cl.clk = clk; + + clk->rate = rate; + + clkdev_add(&clk->cl); +} + +/* + * Linux clock API + */ +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL_GPL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL_GPL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +void __init plat_time_init(void) +{ + struct clk *clk; + + ralink_of_remap(); + + ralink_clk_init(); + clk = clk_get_sys("cpu", NULL); + if (IS_ERR(clk)) + panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); + mips_hpt_frequency = clk_get_rate(clk) / 2; + clk_put(clk); +} -- cgit v1.2.3-59-g8ed1b From 3a5bfe7bdbfd37c9206d7c6dfd7eb9664ccc5038 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:02:01 +0100 Subject: MIPS: ralink: adds OF code Until there is a generic MIPS way of handing the DTB over from bootloader to kernel we rely on a built in devicetrees. The OF code also remaps those register ranges that we use global in our drivers. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4895/ --- arch/mips/ralink/of.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 arch/mips/ralink/of.c diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c new file mode 100644 index 000000000000..4165e70775be --- /dev/null +++ b/arch/mips/ralink/of.c @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2008 Imre Kaloz + * Copyright (C) 2008-2009 Gabor Juhos + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" + +__iomem void *rt_sysc_membase; +__iomem void *rt_memc_membase; + +extern struct boot_param_header __dtb_start; + +__iomem void *plat_of_remap_node(const char *node) +{ + struct resource res; + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, node); + if (!np) + panic("Failed to find %s node", node); + + if (of_address_to_resource(np, 0, &res)) + panic("Failed to get resource for %s", node); + + if ((request_mem_region(res.start, + resource_size(&res), + res.name) < 0)) + panic("Failed to request resources for %s", node); + + return ioremap_nocache(res.start, resource_size(&res)); +} + +void __init device_tree_init(void) +{ + unsigned long base, size; + void *fdt_copy; + + if (!initial_boot_params) + return; + + base = virt_to_phys((void *)initial_boot_params); + size = be32_to_cpu(initial_boot_params->totalsize); + + /* Before we do anything, lets reserve the dt blob */ + reserve_bootmem(base, size, BOOTMEM_DEFAULT); + + /* The strings in the flattened tree are referenced directly by the + * device tree, so copy the flattened device tree from init memory + * to regular memory. + */ + fdt_copy = alloc_bootmem(size); + memcpy(fdt_copy, initial_boot_params, size); + initial_boot_params = fdt_copy; + + unflatten_device_tree(); + + /* free the space reserved for the dt blob */ + free_bootmem(base, size); +} + +void __init plat_mem_setup(void) +{ + set_io_port_base(KSEG1); + + /* + * Load the builtin devicetree. This causes the chosen node to be + * parsed resulting in our memory appearing + */ + __dt_setup_arch(&__dtb_start); +} + +static int __init plat_of_setup(void) +{ + static struct of_device_id of_ids[3]; + int len = sizeof(of_ids[0].compatible); + + if (!of_have_populated_dt()) + panic("device tree not present"); + + strncpy(of_ids[0].compatible, soc_info.compatible, len); + strncpy(of_ids[1].compatible, "palmbus", len); + + if (of_platform_populate(NULL, of_ids, NULL, NULL)) + panic("failed to populate DT\n"); + + return 0; +} + +arch_initcall(plat_of_setup); -- cgit v1.2.3-59-g8ed1b From 5fff610b7c60195de98e68bec00c357f393ce634 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:02:55 +0100 Subject: MIPS: ralink: adds early_printk support Add the code needed to make early printk work. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4897/ --- arch/mips/ralink/early_printk.c | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 arch/mips/ralink/early_printk.c diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c new file mode 100644 index 000000000000..c4ae47eb24ab --- /dev/null +++ b/arch/mips/ralink/early_printk.c @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2011-2012 Gabor Juhos + */ + +#include +#include + +#include + +#define EARLY_UART_BASE 0x10000c00 + +#define UART_REG_RX 0x00 +#define UART_REG_TX 0x04 +#define UART_REG_IER 0x08 +#define UART_REG_IIR 0x0c +#define UART_REG_FCR 0x10 +#define UART_REG_LCR 0x14 +#define UART_REG_MCR 0x18 +#define UART_REG_LSR 0x1c + +static __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE); + +static inline void uart_w32(u32 val, unsigned reg) +{ + __raw_writel(val, uart_membase + reg); +} + +static inline u32 uart_r32(unsigned reg) +{ + return __raw_readl(uart_membase + reg); +} + +void prom_putchar(unsigned char ch) +{ + while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) + ; + uart_w32(ch, UART_REG_TX); + while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) + ; +} -- cgit v1.2.3-59-g8ed1b From 2809b31770d7fd934a748692e1922a5e613f06e5 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:03:46 +0100 Subject: MIPS: ralink: adds support for RT305x SoC family Add support code for rt3050, rt3052, rt3350, rt3352 and rt5350 SOC. The code detects the SoC and registers the clk / pinmux settings. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4896/ --- arch/mips/include/asm/mach-ralink/rt305x.h | 139 +++++++++++++++++ arch/mips/ralink/rt305x.c | 242 +++++++++++++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 arch/mips/include/asm/mach-ralink/rt305x.h create mode 100644 arch/mips/ralink/rt305x.c diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h new file mode 100644 index 000000000000..7d344f2d7d0a --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -0,0 +1,139 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * Copyright (C) 2013 John Crispin + */ + +#ifndef _RT305X_REGS_H_ +#define _RT305X_REGS_H_ + +enum rt305x_soc_type { + RT305X_SOC_UNKNOWN = 0, + RT305X_SOC_RT3050, + RT305X_SOC_RT3052, + RT305X_SOC_RT3350, + RT305X_SOC_RT3352, + RT305X_SOC_RT5350, +}; + +extern enum rt305x_soc_type rt305x_soc; + +static inline int soc_is_rt3050(void) +{ + return rt305x_soc == RT305X_SOC_RT3050; +} + +static inline int soc_is_rt3052(void) +{ + return rt305x_soc == RT305X_SOC_RT3052; +} + +static inline int soc_is_rt305x(void) +{ + return soc_is_rt3050() || soc_is_rt3052(); +} + +static inline int soc_is_rt3350(void) +{ + return rt305x_soc == RT305X_SOC_RT3350; +} + +static inline int soc_is_rt3352(void) +{ + return rt305x_soc == RT305X_SOC_RT3352; +} + +static inline int soc_is_rt5350(void) +{ + return rt305x_soc == RT305X_SOC_RT5350; +} + +#define RT305X_SYSC_BASE 0x10000000 + +#define SYSC_REG_CHIP_NAME0 0x00 +#define SYSC_REG_CHIP_NAME1 0x04 +#define SYSC_REG_CHIP_ID 0x0c +#define SYSC_REG_SYSTEM_CONFIG 0x10 + +#define RT3052_CHIP_NAME0 0x30335452 +#define RT3052_CHIP_NAME1 0x20203235 + +#define RT3350_CHIP_NAME0 0x33335452 +#define RT3350_CHIP_NAME1 0x20203035 + +#define RT3352_CHIP_NAME0 0x33335452 +#define RT3352_CHIP_NAME1 0x20203235 + +#define RT5350_CHIP_NAME0 0x33355452 +#define RT5350_CHIP_NAME1 0x20203035 + +#define CHIP_ID_ID_MASK 0xff +#define CHIP_ID_ID_SHIFT 8 +#define CHIP_ID_REV_MASK 0xff + +#define RT305X_SYSCFG_CPUCLK_SHIFT 18 +#define RT305X_SYSCFG_CPUCLK_MASK 0x1 +#define RT305X_SYSCFG_CPUCLK_LOW 0x0 +#define RT305X_SYSCFG_CPUCLK_HIGH 0x1 + +#define RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT 2 +#define RT305X_SYSCFG_CPUCLK_MASK 0x1 +#define RT305X_SYSCFG_SRAM_CS0_MODE_WDT 0x1 + +#define RT3352_SYSCFG0_CPUCLK_SHIFT 8 +#define RT3352_SYSCFG0_CPUCLK_MASK 0x1 +#define RT3352_SYSCFG0_CPUCLK_LOW 0x0 +#define RT3352_SYSCFG0_CPUCLK_HIGH 0x1 + +#define RT5350_SYSCFG0_CPUCLK_SHIFT 8 +#define RT5350_SYSCFG0_CPUCLK_MASK 0x3 +#define RT5350_SYSCFG0_CPUCLK_360 0x0 +#define RT5350_SYSCFG0_CPUCLK_320 0x2 +#define RT5350_SYSCFG0_CPUCLK_300 0x3 + +/* multi function gpio pins */ +#define RT305X_GPIO_I2C_SD 1 +#define RT305X_GPIO_I2C_SCLK 2 +#define RT305X_GPIO_SPI_EN 3 +#define RT305X_GPIO_SPI_CLK 4 +/* GPIO 7-14 is shared between UART0, PCM and I2S interfaces */ +#define RT305X_GPIO_7 7 +#define RT305X_GPIO_10 10 +#define RT305X_GPIO_14 14 +#define RT305X_GPIO_UART1_TXD 15 +#define RT305X_GPIO_UART1_RXD 16 +#define RT305X_GPIO_JTAG_TDO 17 +#define RT305X_GPIO_JTAG_TDI 18 +#define RT305X_GPIO_MDIO_MDC 22 +#define RT305X_GPIO_MDIO_MDIO 23 +#define RT305X_GPIO_SDRAM_MD16 24 +#define RT305X_GPIO_SDRAM_MD31 39 +#define RT305X_GPIO_GE0_TXD0 40 +#define RT305X_GPIO_GE0_RXCLK 51 + +#define RT305X_GPIO_MODE_I2C BIT(0) +#define RT305X_GPIO_MODE_SPI BIT(1) +#define RT305X_GPIO_MODE_UART0_SHIFT 2 +#define RT305X_GPIO_MODE_UART0_MASK 0x7 +#define RT305X_GPIO_MODE_UART0(x) ((x) << RT305X_GPIO_MODE_UART0_SHIFT) +#define RT305X_GPIO_MODE_UARTF 0x0 +#define RT305X_GPIO_MODE_PCM_UARTF 0x1 +#define RT305X_GPIO_MODE_PCM_I2S 0x2 +#define RT305X_GPIO_MODE_I2S_UARTF 0x3 +#define RT305X_GPIO_MODE_PCM_GPIO 0x4 +#define RT305X_GPIO_MODE_GPIO_UARTF 0x5 +#define RT305X_GPIO_MODE_GPIO_I2S 0x6 +#define RT305X_GPIO_MODE_GPIO 0x7 +#define RT305X_GPIO_MODE_UART1 BIT(5) +#define RT305X_GPIO_MODE_JTAG BIT(6) +#define RT305X_GPIO_MODE_MDIO BIT(7) +#define RT305X_GPIO_MODE_SDRAM BIT(8) +#define RT305X_GPIO_MODE_RGMII BIT(9) + +#endif diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c new file mode 100644 index 000000000000..0a4bbdcf59d9 --- /dev/null +++ b/arch/mips/ralink/rt305x.c @@ -0,0 +1,242 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include + +#include +#include +#include + +#include "common.h" + +enum rt305x_soc_type rt305x_soc; + +struct ralink_pinmux_grp mode_mux[] = { + { + .name = "i2c", + .mask = RT305X_GPIO_MODE_I2C, + .gpio_first = RT305X_GPIO_I2C_SD, + .gpio_last = RT305X_GPIO_I2C_SCLK, + }, { + .name = "spi", + .mask = RT305X_GPIO_MODE_SPI, + .gpio_first = RT305X_GPIO_SPI_EN, + .gpio_last = RT305X_GPIO_SPI_CLK, + }, { + .name = "uartlite", + .mask = RT305X_GPIO_MODE_UART1, + .gpio_first = RT305X_GPIO_UART1_TXD, + .gpio_last = RT305X_GPIO_UART1_RXD, + }, { + .name = "jtag", + .mask = RT305X_GPIO_MODE_JTAG, + .gpio_first = RT305X_GPIO_JTAG_TDO, + .gpio_last = RT305X_GPIO_JTAG_TDI, + }, { + .name = "mdio", + .mask = RT305X_GPIO_MODE_MDIO, + .gpio_first = RT305X_GPIO_MDIO_MDC, + .gpio_last = RT305X_GPIO_MDIO_MDIO, + }, { + .name = "sdram", + .mask = RT305X_GPIO_MODE_SDRAM, + .gpio_first = RT305X_GPIO_SDRAM_MD16, + .gpio_last = RT305X_GPIO_SDRAM_MD31, + }, { + .name = "rgmii", + .mask = RT305X_GPIO_MODE_RGMII, + .gpio_first = RT305X_GPIO_GE0_TXD0, + .gpio_last = RT305X_GPIO_GE0_RXCLK, + }, {0} +}; + +struct ralink_pinmux_grp uart_mux[] = { + { + .name = "uartf", + .mask = RT305X_GPIO_MODE_UARTF, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "pcm uartf", + .mask = RT305X_GPIO_MODE_PCM_UARTF, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "pcm i2s", + .mask = RT305X_GPIO_MODE_PCM_I2S, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "i2s uartf", + .mask = RT305X_GPIO_MODE_I2S_UARTF, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "pcm gpio", + .mask = RT305X_GPIO_MODE_PCM_GPIO, + .gpio_first = RT305X_GPIO_10, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "gpio uartf", + .mask = RT305X_GPIO_MODE_GPIO_UARTF, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "gpio i2s", + .mask = RT305X_GPIO_MODE_GPIO_I2S, + .gpio_first = RT305X_GPIO_7, + .gpio_last = RT305X_GPIO_14, + }, { + .name = "gpio", + .mask = RT305X_GPIO_MODE_GPIO, + }, {0} +}; + +void rt305x_wdt_reset(void) +{ + u32 t; + + /* enable WDT reset output on pin SRAM_CS_N */ + t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); + t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT << + RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT; + rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG); +} + +struct ralink_pinmux gpio_pinmux = { + .mode = mode_mux, + .uart = uart_mux, + .uart_shift = RT305X_GPIO_MODE_UART0_SHIFT, + .wdt_reset = rt305x_wdt_reset, +}; + +void __init ralink_clk_init(void) +{ + unsigned long cpu_rate, sys_rate, wdt_rate, uart_rate; + u32 t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); + + if (soc_is_rt305x() || soc_is_rt3350()) { + t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & + RT305X_SYSCFG_CPUCLK_MASK; + switch (t) { + case RT305X_SYSCFG_CPUCLK_LOW: + cpu_rate = 320000000; + break; + case RT305X_SYSCFG_CPUCLK_HIGH: + cpu_rate = 384000000; + break; + } + sys_rate = uart_rate = wdt_rate = cpu_rate / 3; + } else if (soc_is_rt3352()) { + t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & + RT3352_SYSCFG0_CPUCLK_MASK; + switch (t) { + case RT3352_SYSCFG0_CPUCLK_LOW: + cpu_rate = 384000000; + break; + case RT3352_SYSCFG0_CPUCLK_HIGH: + cpu_rate = 400000000; + break; + } + sys_rate = wdt_rate = cpu_rate / 3; + uart_rate = 40000000; + } else if (soc_is_rt5350()) { + t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & + RT5350_SYSCFG0_CPUCLK_MASK; + switch (t) { + case RT5350_SYSCFG0_CPUCLK_360: + cpu_rate = 360000000; + sys_rate = cpu_rate / 3; + break; + case RT5350_SYSCFG0_CPUCLK_320: + cpu_rate = 320000000; + sys_rate = cpu_rate / 4; + break; + case RT5350_SYSCFG0_CPUCLK_300: + cpu_rate = 300000000; + sys_rate = cpu_rate / 3; + break; + default: + BUG(); + } + uart_rate = 40000000; + wdt_rate = sys_rate; + } else { + BUG(); + } + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000100.timer", wdt_rate); + ralink_clk_add("10000500.uart", uart_rate); + ralink_clk_add("10000c00.uartlite", uart_rate); +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("ralink,rt3050-sysc"); + rt_memc_membase = plat_of_remap_node("ralink,rt3050-memc"); + + if (!rt_sysc_membase || !rt_memc_membase) + panic("Failed to remap core resources"); +} + +void prom_soc_init(struct ralink_soc_info *soc_info) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); + unsigned char *name; + u32 n0; + u32 n1; + u32 id; + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + + if (n0 == RT3052_CHIP_NAME0 && n1 == RT3052_CHIP_NAME1) { + unsigned long icache_sets; + + icache_sets = (read_c0_config1() >> 22) & 7; + if (icache_sets == 1) { + rt305x_soc = RT305X_SOC_RT3050; + name = "RT3050"; + soc_info->compatible = "ralink,rt3050-soc"; + } else { + rt305x_soc = RT305X_SOC_RT3052; + name = "RT3052"; + soc_info->compatible = "ralink,rt3052-soc"; + } + } else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT3350; + name = "RT3350"; + soc_info->compatible = "ralink,rt3350-soc"; + } else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT3352; + name = "RT3352"; + soc_info->compatible = "ralink,rt3352-soc"; + } else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT5350; + name = "RT5350"; + soc_info->compatible = "ralink,rt5350-soc"; + } else { + panic("rt305x: unknown SoC, n0:%08x n1:%08x\n", n0, n1); + } + + id = __raw_readl(sysc + SYSC_REG_CHIP_ID); + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "Ralink %s id:%u rev:%u", + name, + (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, + (id & CHIP_ID_REV_MASK)); +} -- cgit v1.2.3-59-g8ed1b From 5644da4f635a30fc03b4f12d81b2197d716d9cef Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 22 Jan 2013 20:19:33 +0100 Subject: MIPS: ralink: adds rt305x devicetree This adds the devicetree file that describes the rt305x evaluation kit. Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4898/ --- arch/mips/ralink/dts/rt3050.dtsi | 96 ++++++++++++++++++++++++++++++++++++ arch/mips/ralink/dts/rt3052_eval.dts | 52 +++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 arch/mips/ralink/dts/rt3050.dtsi create mode 100644 arch/mips/ralink/dts/rt3052_eval.dts diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi new file mode 100644 index 000000000000..fd49daacbf08 --- /dev/null +++ b/arch/mips/ralink/dts/rt3050.dtsi @@ -0,0 +1,96 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ralink,rt3050-soc", "ralink,rt3052-soc"; + + cpus { + cpu@0 { + compatible = "mips,mips24KEc"; + }; + }; + + chosen { + bootargs = "console=ttyS0,57600 init=/init"; + }; + + palmbus@10000000 { + compatible = "palmbus"; + reg = <0x10000000 0x200000>; + ranges = <0x0 0x10000000 0x1FFFFF>; + + #address-cells = <1>; + #size-cells = <1>; + + sysc@0 { + compatible = "ralink,rt3052-sysc", "ralink,rt3050-sysc"; + reg = <0x0 0x100>; + }; + + timer@100 { + compatible = "ralink,rt3052-wdt", "ralink,rt2880-wdt"; + reg = <0x100 0x100>; + }; + + intc: intc@200 { + compatible = "ralink,rt3052-intc", "ralink,rt2880-intc"; + reg = <0x200 0x100>; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + memc@300 { + compatible = "ralink,rt3052-memc", "ralink,rt3050-memc"; + reg = <0x300 0x100>; + }; + + gpio0: gpio@600 { + compatible = "ralink,rt3052-gpio", "ralink,rt2880-gpio"; + reg = <0x600 0x34>; + + gpio-controller; + #gpio-cells = <2>; + + ralink,ngpio = <24>; + ralink,regs = [ 00 04 08 0c + 20 24 28 2c + 30 34 ]; + }; + + gpio1: gpio@638 { + compatible = "ralink,rt3052-gpio", "ralink,rt2880-gpio"; + reg = <0x638 0x24>; + + gpio-controller; + #gpio-cells = <2>; + + ralink,ngpio = <16>; + ralink,regs = [ 00 04 08 0c + 10 14 18 1c + 20 24 ]; + }; + + gpio2: gpio@660 { + compatible = "ralink,rt3052-gpio", "ralink,rt2880-gpio"; + reg = <0x660 0x24>; + + gpio-controller; + #gpio-cells = <2>; + + ralink,ngpio = <12>; + ralink,regs = [ 00 04 08 0c + 10 14 18 1c + 20 24 ]; + }; + + uartlite@c00 { + compatible = "ralink,rt3052-uart", "ralink,rt2880-uart", "ns16550a"; + reg = <0xc00 0x100>; + + interrupt-parent = <&intc>; + interrupts = <12>; + + reg-shift = <2>; + }; + }; +}; diff --git a/arch/mips/ralink/dts/rt3052_eval.dts b/arch/mips/ralink/dts/rt3052_eval.dts new file mode 100644 index 000000000000..148a590bc419 --- /dev/null +++ b/arch/mips/ralink/dts/rt3052_eval.dts @@ -0,0 +1,52 @@ +/dts-v1/; + +/include/ "rt3050.dtsi" + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ralink,rt3052-eval-board", "ralink,rt3052-soc"; + model = "Ralink RT3052 evaluation board"; + + memory@0 { + reg = <0x0 0x2000000>; + }; + + palmbus@10000000 { + sysc@0 { + ralink,pinmmux = "uartlite", "spi"; + ralink,uartmux = "gpio"; + ralink,wdtmux = <0>; + }; + }; + + cfi@1f000000 { + compatible = "cfi-flash"; + reg = <0x1f000000 0x800000>; + + bank-width = <2>; + device-width = <2>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "uboot"; + reg = <0x0 0x30000>; + read-only; + }; + partition@30000 { + label = "uboot-env"; + reg = <0x30000 0x10000>; + read-only; + }; + partition@40000 { + label = "calibration"; + reg = <0x40000 0x10000>; + read-only; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x7b0000>; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From ae2b5bb6570481b50a7175c64176b82da0a81836 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 20 Jan 2013 22:05:30 +0100 Subject: MIPS: ralink: adds Kbuild files Add the Kbuild symbols and Makefiles needed to actually build the ralink code from this series Signed-off-by: John Crispin Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4899/ --- arch/mips/Kbuild.platforms | 1 + arch/mips/Kconfig | 17 +++++++++++++++++ arch/mips/ralink/Kconfig | 32 ++++++++++++++++++++++++++++++++ arch/mips/ralink/Makefile | 15 +++++++++++++++ arch/mips/ralink/Platform | 10 ++++++++++ arch/mips/ralink/dts/Makefile | 1 + 6 files changed, 76 insertions(+) create mode 100644 arch/mips/ralink/Kconfig create mode 100644 arch/mips/ralink/Makefile create mode 100644 arch/mips/ralink/Platform create mode 100644 arch/mips/ralink/dts/Makefile diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 91b9d69f465c..9a73ce6f4c58 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -22,6 +22,7 @@ platforms += pmc-sierra platforms += pnx833x platforms += pnx8550 platforms += powertv +platforms += ralink platforms += rb532 platforms += sgi-ip22 platforms += sgi-ip27 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8f8666c8f28d..79ad1d09c255 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -437,6 +437,22 @@ config POWERTV help This enables support for the Cisco PowerTV Platform. +config RALINK + bool "Ralink based machines" + select CEVT_R4K + select CSRC_R4K + select BOOT_RAW + select DMA_NONCOHERENT + select IRQ_CPU + select USE_OF + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_HAS_EARLY_PRINTK + select HAVE_MACH_CLKDEV + select CLKDEV_LOOKUP + config SGI_IP22 bool "SGI IP22 (Indy/Indigo2)" select FW_ARC @@ -849,6 +865,7 @@ source "arch/mips/lantiq/Kconfig" source "arch/mips/lasat/Kconfig" source "arch/mips/pmc-sierra/Kconfig" source "arch/mips/powertv/Kconfig" +source "arch/mips/ralink/Kconfig" source "arch/mips/sgi-ip27/Kconfig" source "arch/mips/sibyte/Kconfig" source "arch/mips/txx9/Kconfig" diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig new file mode 100644 index 000000000000..a0b0197cab0a --- /dev/null +++ b/arch/mips/ralink/Kconfig @@ -0,0 +1,32 @@ +if RALINK + +choice + prompt "Ralink SoC selection" + default SOC_RT305X + help + Select Ralink MIPS SoC type. + + config SOC_RT305X + bool "RT305x" + select USB_ARCH_HAS_HCD + select USB_ARCH_HAS_OHCI + select USB_ARCH_HAS_EHCI + +endchoice + +choice + prompt "Devicetree selection" + default DTB_RT_NONE + help + Select the devicetree. + + config DTB_RT_NONE + bool "None" + + config DTB_RT305X_EVAL + bool "RT305x eval kit" + depends on SOC_RT305X + +endchoice + +endif diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile new file mode 100644 index 000000000000..939757f0e71f --- /dev/null +++ b/arch/mips/ralink/Makefile @@ -0,0 +1,15 @@ +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation.# +# Makefile for the Ralink common stuff +# +# Copyright (C) 2009-2011 Gabor Juhos +# Copyright (C) 2013 John Crispin + +obj-y := prom.o of.o reset.o clk.o irq.o + +obj-$(CONFIG_SOC_RT305X) += rt305x.o + +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-y += dts/ diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform new file mode 100644 index 000000000000..6babd65765e6 --- /dev/null +++ b/arch/mips/ralink/Platform @@ -0,0 +1,10 @@ +# +# Ralink SoC common stuff +# +core-$(CONFIG_RALINK) += arch/mips/ralink/ +cflags-$(CONFIG_RALINK) += -I$(srctree)/arch/mips/include/asm/mach-ralink + +# +# Ralink RT305x +# +load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 diff --git a/arch/mips/ralink/dts/Makefile b/arch/mips/ralink/dts/Makefile new file mode 100644 index 000000000000..1a69fb300955 --- /dev/null +++ b/arch/mips/ralink/dts/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DTB_RT305X_EVAL) := rt3052_eval.dtb.o -- cgit v1.2.3-59-g8ed1b From 6d63d70f9fe4c1b3d293ac3b9d2fcaf937d95cea Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 1 Feb 2013 12:50:49 +0100 Subject: MIPS: ralink: adds default config file Signed-off-by: John Crispin --- arch/mips/configs/rt305x_defconfig | 167 +++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 arch/mips/configs/rt305x_defconfig diff --git a/arch/mips/configs/rt305x_defconfig b/arch/mips/configs/rt305x_defconfig new file mode 100644 index 000000000000..d1741bcf8949 --- /dev/null +++ b/arch/mips/configs/rt305x_defconfig @@ -0,0 +1,167 @@ +CONFIG_RALINK=y +CONFIG_DTB_RT305X_EVAL=y +CONFIG_CPU_MIPS32_R2=y +# CONFIG_COMPACTION is not set +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_HZ_100=y +# CONFIG_SECCOMP is not set +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INITRAMFS_ROOT_UID=1000 +CONFIG_INITRAMFS_ROOT_GID=1000 +# CONFIG_RD_GZIP is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_COREDUMP is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_ARPD=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_BRIDGE_NETFILTER is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NF_CONNTRACK_IPV4=m +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_RAW=m +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_HAMRADIO=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_M25P80=y +CONFIG_EEPROM_93CX6=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y +CONFIG_PPP=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_ISDN=y +CONFIG_INPUT=m +CONFIG_INPUT_POLLDEV=m +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_MISC=y +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SPI=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +# CONFIG_HID is not set +# CONFIG_USB_HID is not set +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DEBUG=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_STAGING=y +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_DNOTIFY is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +# CONFIG_JFFS2_ZLIB is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRC_ITU_T=m +CONFIG_CRC32_SARWATE=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_AVERAGE=y -- cgit v1.2.3-59-g8ed1b From dcc7310e144c3bf17a86d2f058d60fb525d4b34a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 31 Jan 2013 13:44:10 +0100 Subject: Document: devicetree: add OF documents for MIPS interrupt controller Signed-off-by: John Crispin Acked-by: David Daney Patchwork: http://patchwork.linux-mips.org/patch/4901/ --- Documentation/devicetree/bindings/mips/cpu_irq.txt | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/mips/cpu_irq.txt diff --git a/Documentation/devicetree/bindings/mips/cpu_irq.txt b/Documentation/devicetree/bindings/mips/cpu_irq.txt new file mode 100644 index 000000000000..13aa4b62c62a --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt @@ -0,0 +1,47 @@ +MIPS CPU interrupt controller + +On MIPS the mips_cpu_intc_init() helper can be used to initialize the 8 CPU +IRQs from a devicetree file and create a irq_domain for IRQ controller. + +With the irq_domain in place we can describe how the 8 IRQs are wired to the +platforms internal interrupt controller cascade. + +Below is an example of a platform describing the cascade inside the devicetree +and the code used to load it inside arch_init_irq(). + +Required properties: +- compatible : Should be "mti,cpu-interrupt-controller" + +Example devicetree: + cpu-irq: cpu-irq@0 { + #address-cells = <0>; + + interrupt-controller; + #interrupt-cells = <1>; + + compatible = "mti,cpu-interrupt-controller"; + }; + + intc: intc@200 { + compatible = "ralink,rt2880-intc"; + reg = <0x200 0x100>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu-irq>; + interrupts = <2>; + }; + + +Example platform irq.c: +static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, + { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + of_irq_init(of_irq_ids); +} -- cgit v1.2.3-59-g8ed1b From 0916b46962cbcac9465d253d0a398435b3965fd5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 31 Jan 2013 12:20:43 +0000 Subject: MIPS: add irqdomain support for the CPU IRQ controller Add code to load a irq_domain for the MIPS IRQ controller from a devicetree file. Signed-off-by: Gabor Juhos Signed-off-by: John Crispin Acked-by: David Daney Patchwork: http://patchwork.linux-mips.org/patch/4902/ --- arch/mips/include/asm/irq_cpu.h | 6 ++++++ arch/mips/kernel/irq_cpu.c | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/arch/mips/include/asm/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h index ef6a07cddb23..3f11fdb3ed8c 100644 --- a/arch/mips/include/asm/irq_cpu.h +++ b/arch/mips/include/asm/irq_cpu.h @@ -17,4 +17,10 @@ extern void mips_cpu_irq_init(void); extern void rm7k_cpu_irq_init(void); extern void rm9k_cpu_irq_init(void); +#ifdef CONFIG_IRQ_DOMAIN +struct device_node; +extern int mips_cpu_intc_init(struct device_node *of_node, + struct device_node *parent); +#endif + #endif /* _ASM_IRQ_CPU_H */ diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 972263bcf403..49bc9caaddf8 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -113,3 +114,44 @@ void __init mips_cpu_irq_init(void) irq_set_chip_and_handler(i, &mips_cpu_irq_controller, handle_percpu_irq); } + +#ifdef CONFIG_IRQ_DOMAIN +static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + static struct irq_chip *chip; + + if (hw < 2 && cpu_has_mipsmt) { + /* Software interrupts are used for MT/CMT IPI */ + chip = &mips_mt_cpu_irq_controller; + } else { + chip = &mips_cpu_irq_controller; + } + + irq_set_chip_and_handler(irq, chip, handle_percpu_irq); + + return 0; +} + +static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = { + .map = mips_cpu_intc_map, + .xlate = irq_domain_xlate_onecell, +}; + +int __init mips_cpu_intc_init(struct device_node *of_node, + struct device_node *parent) +{ + struct irq_domain *domain; + + /* Mask interrupts. */ + clear_c0_status(ST0_IM); + clear_c0_cause(CAUSEF_IP); + + domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0, + &mips_cpu_intc_irq_domain_ops, NULL); + if (!domain) + panic("Failed to add irqdomain for MIPS CPU\n"); + + return 0; +} +#endif /* CONFIG_IRQ_DOMAIN */ -- cgit v1.2.3-59-g8ed1b From d3d2b4200b5a42851365e903d101f8f0882eb9eb Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 31 Jan 2013 20:43:30 +0100 Subject: MIPS: ralink: add CPU interrupt controller to of_irq_ids Convert the ralink IRQ code to make use of the new MIPS IRQ controller OF mappings. Signed-off-by: Gabor Juhos Signed-off-by: John Crispin Acked-by: David Daney Patchwork: http://patchwork.linux-mips.org/patch/4900/ --- arch/mips/ralink/dts/rt3050.dtsi | 10 ++++++++++ arch/mips/ralink/irq.c | 10 +++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/mips/ralink/dts/rt3050.dtsi b/arch/mips/ralink/dts/rt3050.dtsi index fd49daacbf08..069d0660e1dd 100644 --- a/arch/mips/ralink/dts/rt3050.dtsi +++ b/arch/mips/ralink/dts/rt3050.dtsi @@ -13,6 +13,13 @@ bootargs = "console=ttyS0,57600 init=/init"; }; + cpuintc: cpuintc@0 { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + palmbus@10000000 { compatible = "palmbus"; reg = <0x10000000 0x200000>; @@ -37,6 +44,9 @@ interrupt-controller; #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <2>; }; memc@300 { diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index e62c9751e2d8..6d054c5ec9ab 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -128,8 +128,11 @@ static int __init intc_of_init(struct device_node *node, { struct resource res; struct irq_domain *domain; + int irq; - mips_cpu_irq_init(); + irq = irq_of_parse_and_map(node, 0); + if (!irq) + panic("Failed to get INTC IRQ"); if (of_address_to_resource(node, 0, &res)) panic("Failed to get intc memory range"); @@ -156,8 +159,8 @@ static int __init intc_of_init(struct device_node *node, rt_intc_w32(INTC_INT_GLOBAL, INTC_REG_ENABLE); - irq_set_chained_handler(RALINK_CPU_IRQ_INTC, ralink_intc_irq_handler); - irq_set_handler_data(RALINK_CPU_IRQ_INTC, domain); + irq_set_chained_handler(irq, ralink_intc_irq_handler); + irq_set_handler_data(irq, domain); cp0_perfcount_irq = irq_create_mapping(domain, 9); @@ -165,6 +168,7 @@ static int __init intc_of_init(struct device_node *node, } static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; -- cgit v1.2.3-59-g8ed1b From 58d2e9bcd682d76bcb9575dc56c85f1d82a81bfa Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 2 Feb 2013 11:40:42 +0000 Subject: MIPS: pci-ar724x: convert into a platform driver The patch converts the pci-ar724x driver into a platform driver. This makes it possible to register the PCI controller as a plain platform device. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4905/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar724x.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index c11c75be2d7e..e7aca88ba0c0 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -262,7 +264,7 @@ static struct irq_chip ar724x_pci_irq_chip = { .irq_mask_ack = ar724x_pci_irq_mask, }; -static void __init ar724x_pci_irq_init(int irq) +static void ar724x_pci_irq_init(int irq) { void __iomem *base; int i; @@ -282,7 +284,7 @@ static void __init ar724x_pci_irq_init(int irq) irq_set_chained_handler(irq, ar724x_pci_irq_handler); } -int __init ar724x_pcibios_init(int irq) +int ar724x_pcibios_init(int irq) { int ret; @@ -312,3 +314,54 @@ err_unmap_devcfg: err: return ret; } + +static int ar724x_pci_probe(struct platform_device *pdev) +{ + struct resource *res; + int irq; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); + if (!res) + return -EINVAL; + + ar724x_pci_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); + if (ar724x_pci_ctrl_base == NULL) + return -EBUSY; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); + if (!res) + return -EINVAL; + + ar724x_pci_devcfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!ar724x_pci_devcfg_base) + return -EBUSY; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + ar724x_pci_link_up = ar724x_pci_check_link(); + if (!ar724x_pci_link_up) + dev_warn(&pdev->dev, "PCIe link is down\n"); + + ar724x_pci_irq_init(irq); + + register_pci_controller(&ar724x_pci_controller); + + return 0; +} + +static struct platform_driver ar724x_pci_driver = { + .probe = ar724x_pci_probe, + .driver = { + .name = "ar724x-pci", + .owner = THIS_MODULE, + }, +}; + +static int __init ar724x_pci_init(void) +{ + return platform_driver_register(&ar724x_pci_driver); +} + +postcore_initcall(ar724x_pci_init); -- cgit v1.2.3-59-g8ed1b From fb167e891d5cc6386840dd092af2d461b38eb802 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 2 Feb 2013 11:40:43 +0000 Subject: MIPS: pci-ar71xx: convert into a platform driver The patch converts the pci-ar71xx driver into a platform driver. This makes it possible to register the PCI controller as a plain platform device. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4906/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar71xx.c | 60 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 6eaa4f2d0e38..0d8412fc5047 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -309,7 +311,7 @@ static struct irq_chip ar71xx_pci_irq_chip = { .irq_mask_ack = ar71xx_pci_irq_mask, }; -static __init void ar71xx_pci_irq_init(void) +static void ar71xx_pci_irq_init(int irq) { void __iomem *base = ath79_reset_base; int i; @@ -324,10 +326,10 @@ static __init void ar71xx_pci_irq_init(void) irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, handle_level_irq); - irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler); + irq_set_chained_handler(irq, ar71xx_pci_irq_handler); } -static __init void ar71xx_pci_reset(void) +static void ar71xx_pci_reset(void) { void __iomem *ddr_base = ath79_ddr_base; @@ -367,9 +369,59 @@ __init int ar71xx_pcibios_init(void) /* clear bus errors */ ar71xx_pci_check_error(1); - ar71xx_pci_irq_init(); + ar71xx_pci_irq_init(ATH79_CPU_IRQ_IP2); register_pci_controller(&ar71xx_pci_controller); return 0; } + +static int ar71xx_pci_probe(struct platform_device *pdev) +{ + struct resource *res; + int irq; + u32 t; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); + if (!res) + return -EINVAL; + + ar71xx_pcicfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!ar71xx_pcicfg_base) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + ar71xx_pci_reset(); + + /* setup COMMAND register */ + t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; + ar71xx_pci_local_write(PCI_COMMAND, 4, t); + + /* clear bus errors */ + ar71xx_pci_check_error(1); + + ar71xx_pci_irq_init(irq); + + register_pci_controller(&ar71xx_pci_controller); + + return 0; +} + +static struct platform_driver ar71xx_pci_driver = { + .probe = ar71xx_pci_probe, + .driver = { + .name = "ar71xx-pci", + .owner = THIS_MODULE, + }, +}; + +static int __init ar71xx_pci_init(void) +{ + return platform_driver_register(&ar71xx_pci_driver); +} + +postcore_initcall(ar71xx_pci_init); -- cgit v1.2.3-59-g8ed1b From ad4ce92e919f7ad5561a2060deb58899de58b40c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 4 Feb 2013 11:56:53 +0100 Subject: MIPS: ath79: move global PCI defines into a common header The constants will be used by a subsequent patch. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4907/ Signed-off-by: John Crispin --- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 24 ++++++++++++++++++++++++ arch/mips/pci/pci-ar71xx.c | 16 ---------------- arch/mips/pci/pci-ar724x.c | 8 -------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 7d44b5d5f609..7c87bfe6e4ff 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -41,11 +41,35 @@ #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) #define AR71XX_RESET_SIZE 0x100 +#define AR71XX_PCI_MEM_BASE 0x10000000 +#define AR71XX_PCI_MEM_SIZE 0x07000000 + +#define AR71XX_PCI_WIN0_OFFS 0x10000000 +#define AR71XX_PCI_WIN1_OFFS 0x11000000 +#define AR71XX_PCI_WIN2_OFFS 0x12000000 +#define AR71XX_PCI_WIN3_OFFS 0x13000000 +#define AR71XX_PCI_WIN4_OFFS 0x14000000 +#define AR71XX_PCI_WIN5_OFFS 0x15000000 +#define AR71XX_PCI_WIN6_OFFS 0x16000000 +#define AR71XX_PCI_WIN7_OFFS 0x07000000 + +#define AR71XX_PCI_CFG_BASE \ + (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) +#define AR71XX_PCI_CFG_SIZE 0x100 + #define AR7240_USB_CTRL_BASE (AR71XX_APB_BASE + 0x00030000) #define AR7240_USB_CTRL_SIZE 0x100 #define AR7240_OHCI_BASE 0x1b000000 #define AR7240_OHCI_SIZE 0x1000 +#define AR724X_PCI_MEM_BASE 0x10000000 +#define AR724X_PCI_MEM_SIZE 0x04000000 + +#define AR724X_PCI_CFG_BASE 0x14000000 +#define AR724X_PCI_CFG_SIZE 0x1000 +#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) +#define AR724X_PCI_CTRL_SIZE 0x100 + #define AR724X_EHCI_BASE 0x1b000000 #define AR724X_EHCI_SIZE 0x1000 diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 0d8412fc5047..35ee23450d87 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -25,22 +25,6 @@ #include #include -#define AR71XX_PCI_MEM_BASE 0x10000000 -#define AR71XX_PCI_MEM_SIZE 0x07000000 - -#define AR71XX_PCI_WIN0_OFFS 0x10000000 -#define AR71XX_PCI_WIN1_OFFS 0x11000000 -#define AR71XX_PCI_WIN2_OFFS 0x12000000 -#define AR71XX_PCI_WIN3_OFFS 0x13000000 -#define AR71XX_PCI_WIN4_OFFS 0x14000000 -#define AR71XX_PCI_WIN5_OFFS 0x15000000 -#define AR71XX_PCI_WIN6_OFFS 0x16000000 -#define AR71XX_PCI_WIN7_OFFS 0x07000000 - -#define AR71XX_PCI_CFG_BASE \ - (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) -#define AR71XX_PCI_CFG_SIZE 0x100 - #define AR71XX_PCI_REG_CRP_AD_CBE 0x00 #define AR71XX_PCI_REG_CRP_WRDATA 0x04 #define AR71XX_PCI_REG_CRP_RDDATA 0x08 diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index e7aca88ba0c0..b3f9d093c066 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -17,14 +17,6 @@ #include #include -#define AR724X_PCI_CFG_BASE 0x14000000 -#define AR724X_PCI_CFG_SIZE 0x1000 -#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) -#define AR724X_PCI_CTRL_SIZE 0x100 - -#define AR724X_PCI_MEM_BASE 0x10000000 -#define AR724X_PCI_MEM_SIZE 0x04000000 - #define AR724X_PCI_REG_RESET 0x18 #define AR724X_PCI_REG_INT_STATUS 0x4c #define AR724X_PCI_REG_INT_MASK 0x50 -- cgit v1.2.3-59-g8ed1b From 9fc1ca5b73a82daedffa2d1d5daa48dd2093c39a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 2 Feb 2013 11:44:24 +0000 Subject: MIPS: ath79: register platform devices for the PCI controllers The pci-ar71xx and pci-ar724x drivers were converted into platform drivers. Register the corresponding platform devices for the PCI controllers instead of using the ar7{1x,24}x_pcibios_init functions. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4908/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 87 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index ca83abd9d31e..81ef5797944a 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -110,21 +112,88 @@ void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) ath79_pci_plat_dev_init = func; } -int __init ath79_register_pci(void) +static struct platform_device * +ath79_register_pci_ar71xx(void) +{ + struct platform_device *pdev; + struct resource res[2]; + + memset(res, 0, sizeof(res)); + + res[0].name = "cfg_base"; + res[0].flags = IORESOURCE_MEM; + res[0].start = AR71XX_PCI_CFG_BASE; + res[0].end = AR71XX_PCI_CFG_BASE + AR71XX_PCI_CFG_SIZE - 1; + + res[1].flags = IORESOURCE_IRQ; + res[1].start = ATH79_CPU_IRQ_IP2; + res[1].end = ATH79_CPU_IRQ_IP2; + + pdev = platform_device_register_simple("ar71xx-pci", -1, + res, ARRAY_SIZE(res)); + return pdev; +} + +static struct platform_device * +ath79_register_pci_ar724x(int id, + unsigned long cfg_base, + unsigned long ctrl_base, + int irq) { - if (soc_is_ar71xx()) - return ar71xx_pcibios_init(); + struct platform_device *pdev; + struct resource res[3]; - if (soc_is_ar724x()) - return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); + memset(res, 0, sizeof(res)); - if (soc_is_ar9342() || soc_is_ar9344()) { + res[0].name = "cfg_base"; + res[0].flags = IORESOURCE_MEM; + res[0].start = cfg_base; + res[0].end = cfg_base + AR724X_PCI_CFG_SIZE - 1; + + res[1].name = "ctrl_base"; + res[1].flags = IORESOURCE_MEM; + res[1].start = ctrl_base; + res[1].end = ctrl_base + AR724X_PCI_CTRL_SIZE - 1; + + res[2].flags = IORESOURCE_IRQ; + res[2].start = irq; + res[2].end = irq; + + pdev = platform_device_register_simple("ar724x-pci", id, + res, ARRAY_SIZE(res)); + return pdev; +} + +int __init ath79_register_pci(void) +{ + struct platform_device *pdev = NULL; + + if (soc_is_ar71xx()) { + pdev = ath79_register_pci_ar71xx(); + } else if (soc_is_ar724x()) { + pdev = ath79_register_pci_ar724x(-1, + AR724X_PCI_CFG_BASE, + AR724X_PCI_CTRL_BASE, + ATH79_CPU_IRQ_IP2); + } else if (soc_is_ar9342() || + soc_is_ar9344()) { u32 bootstrap; bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); - if (bootstrap & AR934X_BOOTSTRAP_PCIE_RC) - return ar724x_pcibios_init(ATH79_IP2_IRQ(0)); + if ((bootstrap & AR934X_BOOTSTRAP_PCIE_RC) == 0) + return -ENODEV; + + pdev = ath79_register_pci_ar724x(-1, + AR724X_PCI_CFG_BASE, + AR724X_PCI_CTRL_BASE, + ATH79_IP2_IRQ(0)); + } else { + /* No PCI support */ + return -ENODEV; } - return -ENODEV; + if (!pdev) + pr_err("unable to register PCI controller device\n"); + + return pdev ? 0 : -ENODEV; } -- cgit v1.2.3-59-g8ed1b From 6e783865b4e60f2ecf7708f8ea24db5c5ea07ced Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 4 Feb 2013 11:58:49 +0100 Subject: MIPS: ath79: remove unused ar7{1x,24}x_pcibios_init functions The functions are unused now, so remove them. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4909/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 1 - arch/mips/include/asm/mach-ath79/pci.h | 28 ---------------------------- arch/mips/pci/pci-ar71xx.c | 26 -------------------------- arch/mips/pci/pci-ar724x.c | 32 -------------------------------- 4 files changed, 87 deletions(-) delete mode 100644 arch/mips/include/asm/mach-ath79/pci.h diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index 81ef5797944a..c94bcec169ab 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "pci.h" static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h deleted file mode 100644 index 7868f7fa028f..000000000000 --- a/arch/mips/include/asm/mach-ath79/pci.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Atheros AR71XX/AR724X PCI support - * - * Copyright (C) 2011 René Bolldorf - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#ifndef __ASM_MACH_ATH79_PCI_H -#define __ASM_MACH_ATH79_PCI_H - -#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR71XX) -int ar71xx_pcibios_init(void); -#else -static inline int ar71xx_pcibios_init(void) { return 0; } -#endif - -#if defined(CONFIG_PCI_AR724X) -int ar724x_pcibios_init(int irq); -#else -static inline int ar724x_pcibios_init(int irq) { return 0; } -#endif - -#endif /* __ASM_MACH_ATH79_PCI_H */ diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 35ee23450d87..69e0bb47de08 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -23,7 +23,6 @@ #include #include -#include #define AR71XX_PCI_REG_CRP_AD_CBE 0x00 #define AR71XX_PCI_REG_CRP_WRDATA 0x04 @@ -335,31 +334,6 @@ static void ar71xx_pci_reset(void) mdelay(100); } -__init int ar71xx_pcibios_init(void) -{ - u32 t; - - ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE); - if (ar71xx_pcicfg_base == NULL) - return -ENOMEM; - - ar71xx_pci_reset(); - - /* setup COMMAND register */ - t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; - ar71xx_pci_local_write(PCI_COMMAND, 4, t); - - /* clear bus errors */ - ar71xx_pci_check_error(1); - - ar71xx_pci_irq_init(ATH79_CPU_IRQ_IP2); - - register_pci_controller(&ar71xx_pci_controller); - - return 0; -} - static int ar71xx_pci_probe(struct platform_device *pdev) { struct resource *res; diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index b3f9d093c066..8f008d9a112c 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -15,7 +15,6 @@ #include #include #include -#include #define AR724X_PCI_REG_RESET 0x18 #define AR724X_PCI_REG_INT_STATUS 0x4c @@ -276,37 +275,6 @@ static void ar724x_pci_irq_init(int irq) irq_set_chained_handler(irq, ar724x_pci_irq_handler); } -int ar724x_pcibios_init(int irq) -{ - int ret; - - ret = -ENOMEM; - - ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, - AR724X_PCI_CFG_SIZE); - if (ar724x_pci_devcfg_base == NULL) - goto err; - - ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, - AR724X_PCI_CTRL_SIZE); - if (ar724x_pci_ctrl_base == NULL) - goto err_unmap_devcfg; - - ar724x_pci_link_up = ar724x_pci_check_link(); - if (!ar724x_pci_link_up) - pr_warn("ar724x: PCIe link is down\n"); - - ar724x_pci_irq_init(irq); - register_pci_controller(&ar724x_pci_controller); - - return PCIBIOS_SUCCESSFUL; - -err_unmap_devcfg: - iounmap(ar724x_pci_devcfg_base); -err: - return ret; -} - static int ar724x_pci_probe(struct platform_device *pdev) { struct resource *res; -- cgit v1.2.3-59-g8ed1b From 222831787704c9ad9215f6b56f975b233968607c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 2 Feb 2013 13:18:54 +0000 Subject: MIPS: avoid possible resource conflict in register_pci_controller The IO and memory resources of a PCI controller might already have a parent resource set when they are passed to 'register_pci_controller'. If the parent resource is set, the request_resource call will fail due to resource conflict and the current code will not be able to register the PCI controller. Use the parent resource if it is available in the request_resource call to avoid the isssue. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4910/ Signed-off-by: John Crispin --- arch/mips/pci/pci.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index a1843448fad3..eb653994a2f1 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -175,9 +175,20 @@ static DEFINE_MUTEX(pci_scan_mutex); void register_pci_controller(struct pci_controller *hose) { - if (request_resource(&iomem_resource, hose->mem_resource) < 0) + struct resource *parent; + + parent = hose->mem_resource->parent; + if (!parent) + parent = &iomem_resource; + + if (request_resource(parent, hose->mem_resource) < 0) goto out; - if (request_resource(&ioport_resource, hose->io_resource) < 0) { + + parent = hose->io_resource->parent; + if (!parent) + parent = &ioport_resource; + + if (request_resource(parent, hose->io_resource) < 0) { release_resource(hose->mem_resource); goto out; } -- cgit v1.2.3-59-g8ed1b From 15b6dcba427d70e61667c28b45e3f090ff00acb1 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 2 Feb 2013 13:36:48 +0000 Subject: MIPS: add dummy pci_load_of_ranges The pci_load_of_ranges function is only available if CONFIG_OF is selected. If the function is used without CONFIG_OF being enabled it will cause a build error. Add a dummy inline function to avoid this. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4911/ Signed-off-by: John Crispin --- arch/mips/include/asm/pci.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index d69ea743272b..630645ea5d92 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -144,8 +144,13 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) extern char * (*pcibios_plat_setup)(char *str); +#ifdef CONFIG_OF /* this function parses memory ranges from a device node */ extern void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node); +#else +static inline void pci_load_of_ranges(struct pci_controller *hose, + struct device_node *node) {} +#endif #endif /* _ASM_PCI_H */ -- cgit v1.2.3-59-g8ed1b From 617fed41e98417f3ea3e9974be251e125c8796f2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Feb 2013 09:58:37 +0000 Subject: MIPS: ath79: allow to specify bus number in PCI IRQ maps This is needed for multiple PCI bus support. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4913/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 4 +++- arch/mips/ath79/pci.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index c94bcec169ab..d90e07136383 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -75,7 +75,9 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) const struct ath79_pci_irq *entry; entry = &ath79_pci_irq_map[i]; - if (entry->slot == slot && entry->pin == pin) { + if (entry->bus == dev->bus->number && + entry->slot == slot && + entry->pin == pin) { irq = entry->irq; break; } diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h index 51c6625dcc6d..1d00a3803c37 100644 --- a/arch/mips/ath79/pci.h +++ b/arch/mips/ath79/pci.h @@ -14,6 +14,7 @@ #define _ATH79_PCI_H struct ath79_pci_irq { + int bus; u8 slot; u8 pin; int irq; -- cgit v1.2.3-59-g8ed1b From 908339ef25b1d5e80f1c6fab22b9958174708b4a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Feb 2013 09:58:38 +0000 Subject: MIPS: pci-ar724x: use dynamically allocated PCI controller structure The current code uses static variables to store the PCI controller specific data. This works if the system contains one PCI controller only, however it becomes impractical when multiple PCI controllers are present. Move the variables into a dynamically allocated controller specific structure, and use that instead of the static variables. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4912/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar724x.c | 129 ++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 47 deletions(-) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 8f008d9a112c..93ab8778ce10 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -9,6 +9,7 @@ * by the Free Software Foundation. */ +#include #include #include #include @@ -28,38 +29,56 @@ #define AR7240_BAR0_WAR_VALUE 0xffff -static DEFINE_SPINLOCK(ar724x_pci_lock); -static void __iomem *ar724x_pci_devcfg_base; -static void __iomem *ar724x_pci_ctrl_base; +struct ar724x_pci_controller { + void __iomem *devcfg_base; + void __iomem *ctrl_base; -static u32 ar724x_pci_bar0_value; -static bool ar724x_pci_bar0_is_cached; -static bool ar724x_pci_link_up; + int irq; + + bool link_up; + bool bar0_is_cached; + u32 bar0_value; + + spinlock_t lock; + + struct pci_controller pci_controller; +}; -static inline bool ar724x_pci_check_link(void) +static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc) { u32 reset; - reset = __raw_readl(ar724x_pci_ctrl_base + AR724X_PCI_REG_RESET); + reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET); return reset & AR724X_PCI_RESET_LINK_UP; } +static inline struct ar724x_pci_controller * +pci_bus_to_ar724x_controller(struct pci_bus *bus) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *) bus->sysdata; + return container_of(hose, struct ar724x_pci_controller, pci_controller); +} + static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t *value) { + struct ar724x_pci_controller *apc; unsigned long flags; void __iomem *base; u32 data; - if (!ar724x_pci_link_up) + apc = pci_bus_to_ar724x_controller(bus); + if (!apc->link_up) return PCIBIOS_DEVICE_NOT_FOUND; if (devfn) return PCIBIOS_DEVICE_NOT_FOUND; - base = ar724x_pci_devcfg_base; + base = apc->devcfg_base; - spin_lock_irqsave(&ar724x_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -78,17 +97,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, case 4: break; default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_BAD_REGISTER_NUMBER; } - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); if (where == PCI_BASE_ADDRESS_0 && size == 4 && - ar724x_pci_bar0_is_cached) { + apc->bar0_is_cached) { /* use the cached value */ - *value = ar724x_pci_bar0_value; + *value = apc->bar0_value; } else { *value = data; } @@ -99,12 +118,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t value) { + struct ar724x_pci_controller *apc; unsigned long flags; void __iomem *base; u32 data; int s; - if (!ar724x_pci_link_up) + apc = pci_bus_to_ar724x_controller(bus); + if (!apc->link_up) return PCIBIOS_DEVICE_NOT_FOUND; if (devfn) @@ -122,18 +143,18 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, * BAR0 register in order to make the device memory * accessible. */ - ar724x_pci_bar0_is_cached = true; - ar724x_pci_bar0_value = value; + apc->bar0_is_cached = true; + apc->bar0_value = value; value = AR7240_BAR0_WAR_VALUE; } else { - ar724x_pci_bar0_is_cached = false; + apc->bar0_is_cached = false; } } - base = ar724x_pci_devcfg_base; + base = apc->devcfg_base; - spin_lock_irqsave(&ar724x_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -151,7 +172,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, data = value; break; default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_BAD_REGISTER_NUMBER; } @@ -159,7 +180,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, __raw_writel(data, base + (where & ~3)); /* flush write */ __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_SUCCESSFUL; } @@ -183,18 +204,14 @@ static struct resource ar724x_mem_resource = { .flags = IORESOURCE_MEM, }; -static struct pci_controller ar724x_pci_controller = { - .pci_ops = &ar724x_pci_ops, - .io_resource = &ar724x_io_resource, - .mem_resource = &ar724x_mem_resource, -}; - static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { + struct ar724x_pci_controller *apc; void __iomem *base; u32 pending; - base = ar724x_pci_ctrl_base; + apc = irq_get_handler_data(irq); + base = apc->ctrl_base; pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & __raw_readl(base + AR724X_PCI_REG_INT_MASK); @@ -208,10 +225,12 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) static void ar724x_pci_irq_unmask(struct irq_data *d) { + struct ar724x_pci_controller *apc; void __iomem *base; u32 t; - base = ar724x_pci_ctrl_base; + apc = irq_data_get_irq_chip_data(d); + base = apc->ctrl_base; switch (d->irq) { case ATH79_PCI_IRQ(0): @@ -225,10 +244,12 @@ static void ar724x_pci_irq_unmask(struct irq_data *d) static void ar724x_pci_irq_mask(struct irq_data *d) { + struct ar724x_pci_controller *apc; void __iomem *base; u32 t; - base = ar724x_pci_ctrl_base; + apc = irq_data_get_irq_chip_data(d); + base = apc->ctrl_base; switch (d->irq) { case ATH79_PCI_IRQ(0): @@ -255,12 +276,12 @@ static struct irq_chip ar724x_pci_irq_chip = { .irq_mask_ack = ar724x_pci_irq_mask, }; -static void ar724x_pci_irq_init(int irq) +static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc) { void __iomem *base; int i; - base = ar724x_pci_ctrl_base; + base = apc->ctrl_base; __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); @@ -268,45 +289,59 @@ static void ar724x_pci_irq_init(int irq) BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) + i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) { irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, handle_level_irq); + irq_set_chip_data(i, apc); + } - irq_set_chained_handler(irq, ar724x_pci_irq_handler); + irq_set_handler_data(apc->irq, apc); + irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); } static int ar724x_pci_probe(struct platform_device *pdev) { + struct ar724x_pci_controller *apc; struct resource *res; - int irq; + + apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller), + GFP_KERNEL); + if (!apc) + return -ENOMEM; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); if (!res) return -EINVAL; - ar724x_pci_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); - if (ar724x_pci_ctrl_base == NULL) + apc->ctrl_base = devm_request_and_ioremap(&pdev->dev, res); + if (apc->ctrl_base == NULL) return -EBUSY; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); if (!res) return -EINVAL; - ar724x_pci_devcfg_base = devm_request_and_ioremap(&pdev->dev, res); - if (!ar724x_pci_devcfg_base) + apc->devcfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!apc->devcfg_base) return -EBUSY; - irq = platform_get_irq(pdev, 0); - if (irq < 0) + apc->irq = platform_get_irq(pdev, 0); + if (apc->irq < 0) return -EINVAL; - ar724x_pci_link_up = ar724x_pci_check_link(); - if (!ar724x_pci_link_up) + spin_lock_init(&apc->lock); + + apc->pci_controller.pci_ops = &ar724x_pci_ops; + apc->pci_controller.io_resource = &ar724x_io_resource; + apc->pci_controller.mem_resource = &ar724x_mem_resource; + + apc->link_up = ar724x_pci_check_link(apc); + if (!apc->link_up) dev_warn(&pdev->dev, "PCIe link is down\n"); - ar724x_pci_irq_init(irq); + ar724x_pci_irq_init(apc); - register_pci_controller(&ar724x_pci_controller); + register_pci_controller(&apc->pci_controller); return 0; } -- cgit v1.2.3-59-g8ed1b From 34b134aebda89888b6985b7a3139e9cbdf209236 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Feb 2013 09:59:45 +0000 Subject: MIPS: pci-ar724x: remove static PCI IO/MEM resources Static resources become impractical when multiple PCI controllers are present. Move the resources into the platform device registration code and change the probe routine to get those from there platform device's resources. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4914/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 21 ++++++++++++++++++++- arch/mips/pci/pci-ar724x.c | 40 ++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index d90e07136383..45d1112de50d 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -139,10 +139,13 @@ static struct platform_device * ath79_register_pci_ar724x(int id, unsigned long cfg_base, unsigned long ctrl_base, + unsigned long mem_base, + unsigned long mem_size, + unsigned long io_base, int irq) { struct platform_device *pdev; - struct resource res[3]; + struct resource res[5]; memset(res, 0, sizeof(res)); @@ -160,6 +163,16 @@ ath79_register_pci_ar724x(int id, res[2].start = irq; res[2].end = irq; + res[3].name = "mem_base"; + res[3].flags = IORESOURCE_MEM; + res[3].start = mem_base; + res[3].end = mem_base + mem_size - 1; + + res[4].name = "io_base"; + res[4].flags = IORESOURCE_IO; + res[4].start = io_base; + res[4].end = io_base; + pdev = platform_device_register_simple("ar724x-pci", id, res, ARRAY_SIZE(res)); return pdev; @@ -175,6 +188,9 @@ int __init ath79_register_pci(void) pdev = ath79_register_pci_ar724x(-1, AR724X_PCI_CFG_BASE, AR724X_PCI_CTRL_BASE, + AR724X_PCI_MEM_BASE, + AR724X_PCI_MEM_SIZE, + 0, ATH79_CPU_IRQ_IP2); } else if (soc_is_ar9342() || soc_is_ar9344()) { @@ -187,6 +203,9 @@ int __init ath79_register_pci(void) pdev = ath79_register_pci_ar724x(-1, AR724X_PCI_CFG_BASE, AR724X_PCI_CTRL_BASE, + AR724X_PCI_MEM_BASE, + AR724X_PCI_MEM_SIZE, + 0, ATH79_IP2_IRQ(0)); } else { /* No PCI support */ diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 93ab8778ce10..d0d707de6c6c 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -42,6 +42,8 @@ struct ar724x_pci_controller { spinlock_t lock; struct pci_controller pci_controller; + struct resource io_res; + struct resource mem_res; }; static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc) @@ -190,20 +192,6 @@ static struct pci_ops ar724x_pci_ops = { .write = ar724x_pci_write, }; -static struct resource ar724x_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar724x_mem_resource = { - .name = "PCI memory space", - .start = AR724X_PCI_MEM_BASE, - .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM, -}; - static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { struct ar724x_pci_controller *apc; @@ -331,9 +319,29 @@ static int ar724x_pci_probe(struct platform_device *pdev) spin_lock_init(&apc->lock); + res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); + if (!res) + return -EINVAL; + + apc->io_res.parent = res; + apc->io_res.name = "PCI IO space"; + apc->io_res.start = res->start; + apc->io_res.end = res->end; + apc->io_res.flags = IORESOURCE_IO; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); + if (!res) + return -EINVAL; + + apc->mem_res.parent = res; + apc->mem_res.name = "PCI memory space"; + apc->mem_res.start = res->start; + apc->mem_res.end = res->end; + apc->mem_res.flags = IORESOURCE_MEM; + apc->pci_controller.pci_ops = &ar724x_pci_ops; - apc->pci_controller.io_resource = &ar724x_io_resource; - apc->pci_controller.mem_resource = &ar724x_mem_resource; + apc->pci_controller.io_resource = &apc->io_res; + apc->pci_controller.mem_resource = &apc->mem_res; apc->link_up = ar724x_pci_check_link(apc); if (!apc->link_up) -- cgit v1.2.3-59-g8ed1b From 8b66d461187ff61c5755001af7296e6edde48423 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Feb 2013 10:00:16 +0000 Subject: MIPS: pci-ar724x: use per-controller IRQ base Change to the code to use per-controller IRQ base. This is needed for multiple PCI controller support. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4915/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar724x.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index d0d707de6c6c..0440d8800f8a 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -34,6 +34,7 @@ struct ar724x_pci_controller { void __iomem *ctrl_base; int irq; + int irq_base; bool link_up; bool bar0_is_cached; @@ -205,7 +206,7 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) __raw_readl(base + AR724X_PCI_REG_INT_MASK); if (pending & AR724X_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); + generic_handle_irq(apc->irq_base + 0); else spurious_interrupt(); @@ -215,13 +216,15 @@ static void ar724x_pci_irq_unmask(struct irq_data *d) { struct ar724x_pci_controller *apc; void __iomem *base; + int offset; u32 t; apc = irq_data_get_irq_chip_data(d); base = apc->ctrl_base; + offset = apc->irq_base - d->irq; - switch (d->irq) { - case ATH79_PCI_IRQ(0): + switch (offset) { + case 0: t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); __raw_writel(t | AR724X_PCI_INT_DEV0, base + AR724X_PCI_REG_INT_MASK); @@ -234,13 +237,15 @@ static void ar724x_pci_irq_mask(struct irq_data *d) { struct ar724x_pci_controller *apc; void __iomem *base; + int offset; u32 t; apc = irq_data_get_irq_chip_data(d); base = apc->ctrl_base; + offset = apc->irq_base - d->irq; - switch (d->irq) { - case ATH79_PCI_IRQ(0): + switch (offset) { + case 0: t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); __raw_writel(t & ~AR724X_PCI_INT_DEV0, base + AR724X_PCI_REG_INT_MASK); @@ -264,7 +269,8 @@ static struct irq_chip ar724x_pci_irq_chip = { .irq_mask_ack = ar724x_pci_irq_mask, }; -static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc) +static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, + int id) { void __iomem *base; int i; @@ -274,10 +280,10 @@ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc) __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); - BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); + apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT); - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) { + for (i = apc->irq_base; + i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) { irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, handle_level_irq); irq_set_chip_data(i, apc); @@ -291,6 +297,11 @@ static int ar724x_pci_probe(struct platform_device *pdev) { struct ar724x_pci_controller *apc; struct resource *res; + int id; + + id = pdev->id; + if (id == -1) + id = 0; apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller), GFP_KERNEL); @@ -347,7 +358,7 @@ static int ar724x_pci_probe(struct platform_device *pdev) if (!apc->link_up) dev_warn(&pdev->dev, "PCIe link is down\n"); - ar724x_pci_irq_init(apc); + ar724x_pci_irq_init(apc, id); register_pci_controller(&apc->pci_controller); -- cgit v1.2.3-59-g8ed1b From 12401fc28d40aa5bf8bda6991a96b6d7a3dae3ac Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 3 Feb 2013 14:52:47 +0000 Subject: MIPS: pci-ar724x: setup command register of the PCI controller The command register of the PCI controller is not initialized correctly by the bootloader on some boards and this leads to non working PCI bus. Add code to initialize the command register from the Linux code to avoid this. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4916/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 10 +++- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 2 + arch/mips/pci/pci-ar724x.c | 63 ++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index 45d1112de50d..942e3f9184f0 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -139,13 +139,14 @@ static struct platform_device * ath79_register_pci_ar724x(int id, unsigned long cfg_base, unsigned long ctrl_base, + unsigned long crp_base, unsigned long mem_base, unsigned long mem_size, unsigned long io_base, int irq) { struct platform_device *pdev; - struct resource res[5]; + struct resource res[6]; memset(res, 0, sizeof(res)); @@ -173,6 +174,11 @@ ath79_register_pci_ar724x(int id, res[4].start = io_base; res[4].end = io_base; + res[5].name = "crp_base"; + res[5].flags = IORESOURCE_MEM; + res[5].start = crp_base; + res[5].end = crp_base + AR724X_PCI_CRP_SIZE - 1; + pdev = platform_device_register_simple("ar724x-pci", id, res, ARRAY_SIZE(res)); return pdev; @@ -188,6 +194,7 @@ int __init ath79_register_pci(void) pdev = ath79_register_pci_ar724x(-1, AR724X_PCI_CFG_BASE, AR724X_PCI_CTRL_BASE, + AR724X_PCI_CRP_BASE, AR724X_PCI_MEM_BASE, AR724X_PCI_MEM_SIZE, 0, @@ -203,6 +210,7 @@ int __init ath79_register_pci(void) pdev = ath79_register_pci_ar724x(-1, AR724X_PCI_CFG_BASE, AR724X_PCI_CTRL_BASE, + AR724X_PCI_CRP_BASE, AR724X_PCI_MEM_BASE, AR724X_PCI_MEM_SIZE, 0, diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 7c87bfe6e4ff..a77f6ee70ec1 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -67,6 +67,8 @@ #define AR724X_PCI_CFG_BASE 0x14000000 #define AR724X_PCI_CFG_SIZE 0x1000 +#define AR724X_PCI_CRP_BASE (AR71XX_APB_BASE + 0x000c0000) +#define AR724X_PCI_CRP_SIZE 0x1000 #define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) #define AR724X_PCI_CTRL_SIZE 0x100 diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 0440d8800f8a..8a0700d448fe 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -29,9 +29,17 @@ #define AR7240_BAR0_WAR_VALUE 0xffff +#define AR724X_PCI_CMD_INIT (PCI_COMMAND_MEMORY | \ + PCI_COMMAND_MASTER | \ + PCI_COMMAND_INVALIDATE | \ + PCI_COMMAND_PARITY | \ + PCI_COMMAND_SERR | \ + PCI_COMMAND_FAST_BACK) + struct ar724x_pci_controller { void __iomem *devcfg_base; void __iomem *ctrl_base; + void __iomem *crp_base; int irq; int irq_base; @@ -64,6 +72,51 @@ pci_bus_to_ar724x_controller(struct pci_bus *bus) return container_of(hose, struct ar724x_pci_controller, pci_controller); } +static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, + int where, int size, u32 value) +{ + unsigned long flags; + void __iomem *base; + u32 data; + int s; + + WARN_ON(where & (size - 1)); + + if (!apc->link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + + base = apc->crp_base; + + spin_lock_irqsave(&apc->lock, flags); + data = __raw_readl(base + (where & ~3)); + + switch (size) { + case 1: + s = ((where & 3) * 8); + data &= ~(0xff << s); + data |= ((value & 0xff) << s); + break; + case 2: + s = ((where & 2) * 8); + data &= ~(0xffff << s); + data |= ((value & 0xffff) << s); + break; + case 4: + data = value; + break; + default: + spin_unlock_irqrestore(&apc->lock, flags); + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + __raw_writel(data, base + (where & ~3)); + /* flush write */ + __raw_readl(base + (where & ~3)); + spin_unlock_irqrestore(&apc->lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t *value) { @@ -324,6 +377,14 @@ static int ar724x_pci_probe(struct platform_device *pdev) if (!apc->devcfg_base) return -EBUSY; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crp_base"); + if (!res) + return -EINVAL; + + apc->crp_base = devm_request_and_ioremap(&pdev->dev, res); + if (apc->crp_base == NULL) + return -EBUSY; + apc->irq = platform_get_irq(pdev, 0); if (apc->irq < 0) return -EINVAL; @@ -360,6 +421,8 @@ static int ar724x_pci_probe(struct platform_device *pdev) ar724x_pci_irq_init(apc, id); + ar724x_pci_local_write(apc, PCI_COMMAND, 4, AR724X_PCI_CMD_INIT); + register_pci_controller(&apc->pci_controller); return 0; -- cgit v1.2.3-59-g8ed1b From f18118a868f1f7e7bdfea176a204fcc44fae2985 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 7 Feb 2013 19:28:14 +0000 Subject: MIPS: pci-ar71xx: use dynamically allocated PCI controller structure Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4926/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar71xx.c | 84 +++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 69e0bb47de08..44dc5bf720c0 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -48,8 +48,12 @@ #define AR71XX_PCI_IRQ_COUNT 5 -static DEFINE_SPINLOCK(ar71xx_pci_lock); -static void __iomem *ar71xx_pcicfg_base; +struct ar71xx_pci_controller { + void __iomem *cfg_base; + spinlock_t lock; + int irq; + struct pci_controller pci_ctrl; +}; /* Byte lane enable bits */ static const u8 ar71xx_pci_ble_table[4][4] = { @@ -92,9 +96,18 @@ static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, return ret; } -static int ar71xx_pci_check_error(int quiet) +static inline struct ar71xx_pci_controller * +pci_bus_to_ar71xx_controller(struct pci_bus *bus) { - void __iomem *base = ar71xx_pcicfg_base; + struct pci_controller *hose; + + hose = (struct pci_controller *) bus->sysdata; + return container_of(hose, struct ar71xx_pci_controller, pci_ctrl); +} + +static int ar71xx_pci_check_error(struct ar71xx_pci_controller *apc, int quiet) +{ + void __iomem *base = apc->cfg_base; u32 pci_err; u32 ahb_err; @@ -129,9 +142,10 @@ static int ar71xx_pci_check_error(int quiet) return !!(ahb_err | pci_err); } -static inline void ar71xx_pci_local_write(int where, int size, u32 value) +static inline void ar71xx_pci_local_write(struct ar71xx_pci_controller *apc, + int where, int size, u32 value) { - void __iomem *base = ar71xx_pcicfg_base; + void __iomem *base = apc->cfg_base; u32 ad_cbe; value = value << (8 * (where & 3)); @@ -147,7 +161,8 @@ static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 cmd) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; u32 addr; addr = ar71xx_pci_bus_addr(bus, devfn, where); @@ -156,13 +171,14 @@ static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), base + AR71XX_PCI_REG_CFG_CBE); - return ar71xx_pci_check_error(1); + return ar71xx_pci_check_error(apc, 1); } static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; unsigned long flags; u32 data; int err; @@ -171,7 +187,7 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ret = PCIBIOS_SUCCESSFUL; data = ~0; - spin_lock_irqsave(&ar71xx_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_READ); @@ -180,7 +196,7 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, else data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; @@ -190,7 +206,8 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; unsigned long flags; int err; int ret; @@ -198,7 +215,7 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, value = value << (8 * (where & 3)); ret = PCIBIOS_SUCCESSFUL; - spin_lock_irqsave(&ar71xx_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_WRITE); @@ -207,7 +224,7 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, else __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return ret; } @@ -231,12 +248,6 @@ static struct resource ar71xx_pci_mem_resource = { .flags = IORESOURCE_MEM }; -static struct pci_controller ar71xx_pci_controller = { - .pci_ops = &ar71xx_pci_ops, - .mem_resource = &ar71xx_pci_mem_resource, - .io_resource = &ar71xx_pci_io_resource, -}; - static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *base = ath79_reset_base; @@ -294,7 +305,7 @@ static struct irq_chip ar71xx_pci_irq_chip = { .irq_mask_ack = ar71xx_pci_irq_mask, }; -static void ar71xx_pci_irq_init(int irq) +static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) { void __iomem *base = ath79_reset_base; int i; @@ -309,7 +320,7 @@ static void ar71xx_pci_irq_init(int irq) irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, handle_level_irq); - irq_set_chained_handler(irq, ar71xx_pci_irq_handler); + irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); } static void ar71xx_pci_reset(void) @@ -336,20 +347,27 @@ static void ar71xx_pci_reset(void) static int ar71xx_pci_probe(struct platform_device *pdev) { + struct ar71xx_pci_controller *apc; struct resource *res; - int irq; u32 t; + apc = devm_kzalloc(&pdev->dev, sizeof(struct ar71xx_pci_controller), + GFP_KERNEL); + if (!apc) + return -ENOMEM; + + spin_lock_init(&apc->lock); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); if (!res) return -EINVAL; - ar71xx_pcicfg_base = devm_request_and_ioremap(&pdev->dev, res); - if (!ar71xx_pcicfg_base) + apc->cfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!apc->cfg_base) return -ENOMEM; - irq = platform_get_irq(pdev, 0); - if (irq < 0) + apc->irq = platform_get_irq(pdev, 0); + if (apc->irq < 0) return -EINVAL; ar71xx_pci_reset(); @@ -357,14 +375,18 @@ static int ar71xx_pci_probe(struct platform_device *pdev) /* setup COMMAND register */ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; - ar71xx_pci_local_write(PCI_COMMAND, 4, t); + ar71xx_pci_local_write(apc, PCI_COMMAND, 4, t); /* clear bus errors */ - ar71xx_pci_check_error(1); + ar71xx_pci_check_error(apc, 1); + + ar71xx_pci_irq_init(apc); - ar71xx_pci_irq_init(irq); + apc->pci_ctrl.pci_ops = &ar71xx_pci_ops; + apc->pci_ctrl.mem_resource = &ar71xx_pci_mem_resource; + apc->pci_ctrl.io_resource = &ar71xx_pci_io_resource; - register_pci_controller(&ar71xx_pci_controller); + register_pci_controller(&apc->pci_ctrl); return 0; } -- cgit v1.2.3-59-g8ed1b From 42cb60d1fab4c81ef24876d985e08fc5bb899e41 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 7 Feb 2013 19:28:15 +0000 Subject: MIPS: pci-ar71xx: remove static PCI IO/MEM resources Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4927/ Signed-off-by: John Crispin --- arch/mips/ath79/pci.c | 12 +++++++++++- arch/mips/pci/pci-ar71xx.c | 40 ++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index 942e3f9184f0..ea8aa10893d8 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -117,7 +117,7 @@ static struct platform_device * ath79_register_pci_ar71xx(void) { struct platform_device *pdev; - struct resource res[2]; + struct resource res[4]; memset(res, 0, sizeof(res)); @@ -130,6 +130,16 @@ ath79_register_pci_ar71xx(void) res[1].start = ATH79_CPU_IRQ_IP2; res[1].end = ATH79_CPU_IRQ_IP2; + res[2].name = "io_base"; + res[2].flags = IORESOURCE_IO; + res[2].start = 0; + res[2].end = 0; + + res[3].name = "mem_base"; + res[3].flags = IORESOURCE_MEM; + res[3].start = AR71XX_PCI_MEM_BASE; + res[3].end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1; + pdev = platform_device_register_simple("ar71xx-pci", -1, res, ARRAY_SIZE(res)); return pdev; diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 44dc5bf720c0..e48dddbb4919 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -53,6 +53,8 @@ struct ar71xx_pci_controller { spinlock_t lock; int irq; struct pci_controller pci_ctrl; + struct resource io_res; + struct resource mem_res; }; /* Byte lane enable bits */ @@ -234,20 +236,6 @@ static struct pci_ops ar71xx_pci_ops = { .write = ar71xx_pci_write_config, }; -static struct resource ar71xx_pci_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar71xx_pci_mem_resource = { - .name = "PCI memory space", - .start = AR71XX_PCI_MEM_BASE, - .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *base = ath79_reset_base; @@ -370,6 +358,26 @@ static int ar71xx_pci_probe(struct platform_device *pdev) if (apc->irq < 0) return -EINVAL; + res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); + if (!res) + return -EINVAL; + + apc->io_res.parent = res; + apc->io_res.name = "PCI IO space"; + apc->io_res.start = res->start; + apc->io_res.end = res->end; + apc->io_res.flags = IORESOURCE_IO; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); + if (!res) + return -EINVAL; + + apc->mem_res.parent = res; + apc->mem_res.name = "PCI memory space"; + apc->mem_res.start = res->start; + apc->mem_res.end = res->end; + apc->mem_res.flags = IORESOURCE_MEM; + ar71xx_pci_reset(); /* setup COMMAND register */ @@ -383,8 +391,8 @@ static int ar71xx_pci_probe(struct platform_device *pdev) ar71xx_pci_irq_init(apc); apc->pci_ctrl.pci_ops = &ar71xx_pci_ops; - apc->pci_ctrl.mem_resource = &ar71xx_pci_mem_resource; - apc->pci_ctrl.io_resource = &ar71xx_pci_io_resource; + apc->pci_ctrl.mem_resource = &apc->mem_res; + apc->pci_ctrl.io_resource = &apc->io_res; register_pci_controller(&apc->pci_ctrl); -- cgit v1.2.3-59-g8ed1b From 326e8d17d73fdf213f6334917ef46b2ba7b1354a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 7 Feb 2013 19:29:38 +0000 Subject: MIPS: pci-ar71xx: move irq base to the controller structure Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4928/ Signed-off-by: John Crispin --- arch/mips/pci/pci-ar71xx.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index e48dddbb4919..412ec025cf55 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -52,6 +52,7 @@ struct ar71xx_pci_controller { void __iomem *cfg_base; spinlock_t lock; int irq; + int irq_base; struct pci_controller pci_ctrl; struct resource io_res; struct resource mem_res; @@ -238,23 +239,26 @@ static struct pci_ops ar71xx_pci_ops = { static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { + struct ar71xx_pci_controller *apc; void __iomem *base = ath79_reset_base; u32 pending; + apc = irq_get_handler_data(irq); + pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); if (pending & AR71XX_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); + generic_handle_irq(apc->irq_base + 0); else if (pending & AR71XX_PCI_INT_DEV1) - generic_handle_irq(ATH79_PCI_IRQ(1)); + generic_handle_irq(apc->irq_base + 1); else if (pending & AR71XX_PCI_INT_DEV2) - generic_handle_irq(ATH79_PCI_IRQ(2)); + generic_handle_irq(apc->irq_base + 2); else if (pending & AR71XX_PCI_INT_CORE) - generic_handle_irq(ATH79_PCI_IRQ(4)); + generic_handle_irq(apc->irq_base + 4); else spurious_interrupt(); @@ -262,10 +266,14 @@ static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) static void ar71xx_pci_irq_unmask(struct irq_data *d) { - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; + struct ar71xx_pci_controller *apc; + unsigned int irq; void __iomem *base = ath79_reset_base; u32 t; + apc = irq_data_get_irq_chip_data(d); + irq = d->irq - apc->irq_base; + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -275,10 +283,14 @@ static void ar71xx_pci_irq_unmask(struct irq_data *d) static void ar71xx_pci_irq_mask(struct irq_data *d) { - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; + struct ar71xx_pci_controller *apc; + unsigned int irq; void __iomem *base = ath79_reset_base; u32 t; + apc = irq_data_get_irq_chip_data(d); + irq = d->irq - apc->irq_base; + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -303,11 +315,15 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) + apc->irq_base = ATH79_PCI_IRQ_BASE; + for (i = apc->irq_base; + i < apc->irq_base + AR71XX_PCI_IRQ_COUNT; i++) { irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, handle_level_irq); + irq_set_chip_data(i, apc); + } + irq_set_handler_data(apc->irq, apc); irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); } -- cgit v1.2.3-59-g8ed1b From 7e69c10a8ee1f201c040997c6742c27e915730ad Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 7 Feb 2013 19:32:23 +0000 Subject: ath79: add ATH79_CPU_IRQ() macro Remove the individual ATH79_CPU_IRQ_* constants and use the new macro instead of those. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4929/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-usb.c | 12 ++++++------ arch/mips/ath79/dev-wmac.c | 8 ++++---- arch/mips/ath79/irq.c | 32 ++++++++++++++++---------------- arch/mips/ath79/pci.c | 6 +++--- arch/mips/include/asm/mach-ath79/irq.h | 9 ++------- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index bd2bc108e1b5..2e041977c854 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -111,7 +111,7 @@ static void __init ath79_usb_setup(void) platform_device_register(&ath79_ohci_device); ath79_usb_init_resource(ath79_ehci_resources, AR71XX_EHCI_BASE, - AR71XX_EHCI_SIZE, ATH79_CPU_IRQ_USB); + AR71XX_EHCI_SIZE, ATH79_CPU_IRQ(3)); ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v1; platform_device_register(&ath79_ehci_device); } @@ -136,7 +136,7 @@ static void __init ar7240_usb_setup(void) iounmap(usb_ctrl_base); ath79_usb_init_resource(ath79_ohci_resources, AR7240_OHCI_BASE, - AR7240_OHCI_SIZE, ATH79_CPU_IRQ_USB); + AR7240_OHCI_SIZE, ATH79_CPU_IRQ(3)); platform_device_register(&ath79_ohci_device); } @@ -152,7 +152,7 @@ static void __init ar724x_usb_setup(void) mdelay(10); ath79_usb_init_resource(ath79_ehci_resources, AR724X_EHCI_BASE, - AR724X_EHCI_SIZE, ATH79_CPU_IRQ_USB); + AR724X_EHCI_SIZE, ATH79_CPU_IRQ(3)); ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; platform_device_register(&ath79_ehci_device); } @@ -169,7 +169,7 @@ static void __init ar913x_usb_setup(void) mdelay(10); ath79_usb_init_resource(ath79_ehci_resources, AR913X_EHCI_BASE, - AR913X_EHCI_SIZE, ATH79_CPU_IRQ_USB); + AR913X_EHCI_SIZE, ATH79_CPU_IRQ(3)); ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; platform_device_register(&ath79_ehci_device); } @@ -186,7 +186,7 @@ static void __init ar933x_usb_setup(void) mdelay(10); ath79_usb_init_resource(ath79_ehci_resources, AR933X_EHCI_BASE, - AR933X_EHCI_SIZE, ATH79_CPU_IRQ_USB); + AR933X_EHCI_SIZE, ATH79_CPU_IRQ(3)); ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; platform_device_register(&ath79_ehci_device); } @@ -212,7 +212,7 @@ static void __init ar934x_usb_setup(void) udelay(1000); ath79_usb_init_resource(ath79_ehci_resources, AR934X_EHCI_BASE, - AR934X_EHCI_SIZE, ATH79_CPU_IRQ_USB); + AR934X_EHCI_SIZE, ATH79_CPU_IRQ(3)); ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; platform_device_register(&ath79_ehci_device); } diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c index d6d893c16ad4..4f6c4e389172 100644 --- a/arch/mips/ath79/dev-wmac.c +++ b/arch/mips/ath79/dev-wmac.c @@ -55,8 +55,8 @@ static void __init ar913x_wmac_setup(void) ath79_wmac_resources[0].start = AR913X_WMAC_BASE; ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1; - ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; - ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; + ath79_wmac_resources[1].start = ATH79_CPU_IRQ(2); + ath79_wmac_resources[1].end = ATH79_CPU_IRQ(2); } @@ -83,8 +83,8 @@ static void __init ar933x_wmac_setup(void) ath79_wmac_resources[0].start = AR933X_WMAC_BASE; ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1; - ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; - ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; + ath79_wmac_resources[1].start = ATH79_CPU_IRQ(2); + ath79_wmac_resources[1].end = ATH79_CPU_IRQ(2); t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); if (t & AR933X_BOOTSTRAP_REF_CLK_40) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 219cfa1f5961..29348956d15d 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -114,7 +114,7 @@ static void __init ath79_misc_irq_init(void) handle_level_irq); } - irq_set_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); + irq_set_chained_handler(ATH79_CPU_IRQ(6), ath79_misc_irq_handler); } static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) @@ -147,7 +147,7 @@ static void ar934x_ip2_irq_init(void) irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq); - irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar934x_ip2_irq_dispatch); + irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch); } asmlinkage void plat_irq_dispatch(void) @@ -157,22 +157,22 @@ asmlinkage void plat_irq_dispatch(void) pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & STATUSF_IP7) - do_IRQ(ATH79_CPU_IRQ_TIMER); + do_IRQ(ATH79_CPU_IRQ(7)); else if (pending & STATUSF_IP2) ath79_ip2_handler(); else if (pending & STATUSF_IP4) - do_IRQ(ATH79_CPU_IRQ_GE0); + do_IRQ(ATH79_CPU_IRQ(4)); else if (pending & STATUSF_IP5) - do_IRQ(ATH79_CPU_IRQ_GE1); + do_IRQ(ATH79_CPU_IRQ(5)); else if (pending & STATUSF_IP3) ath79_ip3_handler(); else if (pending & STATUSF_IP6) - do_IRQ(ATH79_CPU_IRQ_MISC); + do_IRQ(ATH79_CPU_IRQ(6)); else spurious_interrupt(); @@ -188,60 +188,60 @@ asmlinkage void plat_irq_dispatch(void) static void ar71xx_ip2_handler(void) { ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI); - do_IRQ(ATH79_CPU_IRQ_IP2); + do_IRQ(ATH79_CPU_IRQ(2)); } static void ar724x_ip2_handler(void) { ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE); - do_IRQ(ATH79_CPU_IRQ_IP2); + do_IRQ(ATH79_CPU_IRQ(2)); } static void ar913x_ip2_handler(void) { ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC); - do_IRQ(ATH79_CPU_IRQ_IP2); + do_IRQ(ATH79_CPU_IRQ(2)); } static void ar933x_ip2_handler(void) { ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC); - do_IRQ(ATH79_CPU_IRQ_IP2); + do_IRQ(ATH79_CPU_IRQ(2)); } static void ar934x_ip2_handler(void) { - do_IRQ(ATH79_CPU_IRQ_IP2); + do_IRQ(ATH79_CPU_IRQ(2)); } static void ar71xx_ip3_handler(void) { ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); + do_IRQ(ATH79_CPU_IRQ(3)); } static void ar724x_ip3_handler(void) { ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); + do_IRQ(ATH79_CPU_IRQ(3)); } static void ar913x_ip3_handler(void) { ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); + do_IRQ(ATH79_CPU_IRQ(3)); } static void ar933x_ip3_handler(void) { ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); + do_IRQ(ATH79_CPU_IRQ(3)); } static void ar934x_ip3_handler(void) { ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); + do_IRQ(ATH79_CPU_IRQ(3)); } void __init arch_init_irq(void) diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index ea8aa10893d8..4350c252bce5 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -127,8 +127,8 @@ ath79_register_pci_ar71xx(void) res[0].end = AR71XX_PCI_CFG_BASE + AR71XX_PCI_CFG_SIZE - 1; res[1].flags = IORESOURCE_IRQ; - res[1].start = ATH79_CPU_IRQ_IP2; - res[1].end = ATH79_CPU_IRQ_IP2; + res[1].start = ATH79_CPU_IRQ(2); + res[1].end = ATH79_CPU_IRQ(2); res[2].name = "io_base"; res[2].flags = IORESOURCE_IO; @@ -208,7 +208,7 @@ int __init ath79_register_pci(void) AR724X_PCI_MEM_BASE, AR724X_PCI_MEM_SIZE, 0, - ATH79_CPU_IRQ_IP2); + ATH79_CPU_IRQ(2)); } else if (soc_is_ar9342() || soc_is_ar9344()) { u32 bootstrap; diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h index 158ad7f41313..3dda4c24571d 100644 --- a/arch/mips/include/asm/mach-ath79/irq.h +++ b/arch/mips/include/asm/mach-ath79/irq.h @@ -12,6 +12,8 @@ #define MIPS_CPU_IRQ_BASE 0 #define NR_IRQS 48 +#define ATH79_CPU_IRQ(_x) (MIPS_CPU_IRQ_BASE + (_x)) + #define ATH79_MISC_IRQ_BASE 8 #define ATH79_MISC_IRQ_COUNT 32 #define ATH79_MISC_IRQ(_x) (ATH79_MISC_IRQ_BASE + (_x)) @@ -24,13 +26,6 @@ #define ATH79_IP2_IRQ_COUNT 2 #define ATH79_IP2_IRQ(_x) (ATH79_IP2_IRQ_BASE + (_x)) -#define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) -#define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) -#define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) -#define ATH79_CPU_IRQ_GE1 (MIPS_CPU_IRQ_BASE + 5) -#define ATH79_CPU_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) -#define ATH79_CPU_IRQ_TIMER (MIPS_CPU_IRQ_BASE + 7) - #define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0) #define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1) #define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2) -- cgit v1.2.3-59-g8ed1b From fd633cf1cfe978003888dc78ff94f926fbe7dd8a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 7 Feb 2013 19:32:24 +0000 Subject: ath79: remove ATH79_MISC_IRQ_* defines Use the ATH79_MISC_IRQ() macro instead. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4930/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-common.c | 6 +++--- arch/mips/ath79/dev-usb.c | 2 +- arch/mips/ath79/irq.c | 2 +- arch/mips/include/asm/mach-ath79/irq.h | 13 ------------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c index 45efc63b08b6..480f5eb9d300 100644 --- a/arch/mips/ath79/dev-common.c +++ b/arch/mips/ath79/dev-common.c @@ -36,7 +36,7 @@ static struct resource ath79_uart_resources[] = { static struct plat_serial8250_port ath79_uart_data[] = { { .mapbase = AR71XX_UART_BASE, - .irq = ATH79_MISC_IRQ_UART, + .irq = ATH79_MISC_IRQ(3), .flags = AR71XX_UART_FLAGS, .iotype = UPIO_MEM32, .regshift = 2, @@ -62,8 +62,8 @@ static struct resource ar933x_uart_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = ATH79_MISC_IRQ_UART, - .end = ATH79_MISC_IRQ_UART, + .start = ATH79_MISC_IRQ(3), + .end = ATH79_MISC_IRQ(3), .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index 2e041977c854..bcb165b17cae 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -107,7 +107,7 @@ static void __init ath79_usb_setup(void) mdelay(900); ath79_usb_init_resource(ath79_ohci_resources, AR71XX_OHCI_BASE, - AR71XX_OHCI_SIZE, ATH79_MISC_IRQ_OHCI); + AR71XX_OHCI_SIZE, ATH79_MISC_IRQ(6)); platform_device_register(&ath79_ohci_device); ath79_usb_init_resource(ath79_ehci_resources, AR71XX_EHCI_BASE, diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 29348956d15d..df88d49bcb05 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -265,7 +265,7 @@ void __init arch_init_irq(void) BUG(); } - cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; + cp0_perfcount_irq = ATH79_MISC_IRQ(5); mips_cpu_irq_init(); ath79_misc_irq_init(); diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h index 3dda4c24571d..23e2bba42482 100644 --- a/arch/mips/include/asm/mach-ath79/irq.h +++ b/arch/mips/include/asm/mach-ath79/irq.h @@ -26,19 +26,6 @@ #define ATH79_IP2_IRQ_COUNT 2 #define ATH79_IP2_IRQ(_x) (ATH79_IP2_IRQ_BASE + (_x)) -#define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0) -#define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1) -#define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2) -#define ATH79_MISC_IRQ_UART (ATH79_MISC_IRQ_BASE + 3) -#define ATH79_MISC_IRQ_WDOG (ATH79_MISC_IRQ_BASE + 4) -#define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5) -#define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6) -#define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7) -#define ATH79_MISC_IRQ_TIMER2 (ATH79_MISC_IRQ_BASE + 8) -#define ATH79_MISC_IRQ_TIMER3 (ATH79_MISC_IRQ_BASE + 9) -#define ATH79_MISC_IRQ_TIMER4 (ATH79_MISC_IRQ_BASE + 10) -#define ATH79_MISC_IRQ_ETHSW (ATH79_MISC_IRQ_BASE + 12) - #include_next #endif /* __ASM_MACH_ATH79_IRQ_H */ -- cgit v1.2.3-59-g8ed1b From 90a938d1add4859ad3e43c3dd5ee54bd0627e42d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sat, 9 Feb 2013 17:57:52 +0000 Subject: MIPS: ath79: use dynamically allocated USB platform devices The current code uses static resources and static platform device instances for the possible USB controllers in the system. These static variables contains initial values which leads to data segment pollution. Remove the static variables and use dynamically allocated structures instead. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4933/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-usb.c | 111 +++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index bcb165b17cae..02124d02cf6e 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -25,29 +25,11 @@ #include "common.h" #include "dev-usb.h" -static struct resource ath79_ohci_resources[2]; - -static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32); +static u64 ath79_usb_dmamask = DMA_BIT_MASK(32); static struct usb_ohci_pdata ath79_ohci_pdata = { }; -static struct platform_device ath79_ohci_device = { - .name = "ohci-platform", - .id = -1, - .resource = ath79_ohci_resources, - .num_resources = ARRAY_SIZE(ath79_ohci_resources), - .dev = { - .dma_mask = &ath79_ohci_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &ath79_ohci_pdata, - }, -}; - -static struct resource ath79_ehci_resources[2]; - -static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32); - static struct usb_ehci_pdata ath79_ehci_pdata_v1 = { .has_synopsys_hc_bug = 1, }; @@ -57,22 +39,16 @@ static struct usb_ehci_pdata ath79_ehci_pdata_v2 = { .has_tt = 1, }; -static struct platform_device ath79_ehci_device = { - .name = "ehci-platform", - .id = -1, - .resource = ath79_ehci_resources, - .num_resources = ARRAY_SIZE(ath79_ehci_resources), - .dev = { - .dma_mask = &ath79_ehci_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static void __init ath79_usb_init_resource(struct resource res[2], - unsigned long base, - unsigned long size, - int irq) +static void __init ath79_usb_register(const char *name, int id, + unsigned long base, unsigned long size, + int irq, const void *data, + size_t data_size) { + struct resource res[2]; + struct platform_device *pdev; + + memset(res, 0, sizeof(res)); + res[0].flags = IORESOURCE_MEM; res[0].start = base; res[0].end = base + size - 1; @@ -80,6 +56,19 @@ static void __init ath79_usb_init_resource(struct resource res[2], res[1].flags = IORESOURCE_IRQ; res[1].start = irq; res[1].end = irq; + + pdev = platform_device_register_resndata(NULL, name, id, + res, ARRAY_SIZE(res), + data, data_size); + + if (IS_ERR(pdev)) { + pr_err("ath79: unable to register USB at %08lx, err=%d\n", + base, (int) PTR_ERR(pdev)); + return; + } + + pdev->dev.dma_mask = &ath79_usb_dmamask; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); } #define AR71XX_USB_RESET_MASK (AR71XX_RESET_USB_HOST | \ @@ -106,14 +95,15 @@ static void __init ath79_usb_setup(void) mdelay(900); - ath79_usb_init_resource(ath79_ohci_resources, AR71XX_OHCI_BASE, - AR71XX_OHCI_SIZE, ATH79_MISC_IRQ(6)); - platform_device_register(&ath79_ohci_device); + ath79_usb_register("ohci-platform", -1, + AR71XX_OHCI_BASE, AR71XX_OHCI_SIZE, + ATH79_MISC_IRQ(6), + &ath79_ohci_pdata, sizeof(ath79_ohci_pdata)); - ath79_usb_init_resource(ath79_ehci_resources, AR71XX_EHCI_BASE, - AR71XX_EHCI_SIZE, ATH79_CPU_IRQ(3)); - ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v1; - platform_device_register(&ath79_ehci_device); + ath79_usb_register("ehci-platform", -1, + AR71XX_EHCI_BASE, AR71XX_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v1, sizeof(ath79_ehci_pdata_v1)); } static void __init ar7240_usb_setup(void) @@ -135,9 +125,10 @@ static void __init ar7240_usb_setup(void) iounmap(usb_ctrl_base); - ath79_usb_init_resource(ath79_ohci_resources, AR7240_OHCI_BASE, - AR7240_OHCI_SIZE, ATH79_CPU_IRQ(3)); - platform_device_register(&ath79_ohci_device); + ath79_usb_register("ohci-platform", -1, + AR7240_OHCI_BASE, AR7240_OHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ohci_pdata, sizeof(ath79_ohci_pdata)); } static void __init ar724x_usb_setup(void) @@ -151,10 +142,10 @@ static void __init ar724x_usb_setup(void) ath79_device_reset_clear(AR724X_RESET_USB_PHY); mdelay(10); - ath79_usb_init_resource(ath79_ehci_resources, AR724X_EHCI_BASE, - AR724X_EHCI_SIZE, ATH79_CPU_IRQ(3)); - ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; - platform_device_register(&ath79_ehci_device); + ath79_usb_register("ehci-platform", -1, + AR724X_EHCI_BASE, AR724X_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); } static void __init ar913x_usb_setup(void) @@ -168,10 +159,10 @@ static void __init ar913x_usb_setup(void) ath79_device_reset_clear(AR913X_RESET_USB_PHY); mdelay(10); - ath79_usb_init_resource(ath79_ehci_resources, AR913X_EHCI_BASE, - AR913X_EHCI_SIZE, ATH79_CPU_IRQ(3)); - ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; - platform_device_register(&ath79_ehci_device); + ath79_usb_register("ehci-platform", -1, + AR913X_EHCI_BASE, AR913X_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); } static void __init ar933x_usb_setup(void) @@ -185,10 +176,10 @@ static void __init ar933x_usb_setup(void) ath79_device_reset_clear(AR933X_RESET_USB_PHY); mdelay(10); - ath79_usb_init_resource(ath79_ehci_resources, AR933X_EHCI_BASE, - AR933X_EHCI_SIZE, ATH79_CPU_IRQ(3)); - ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; - platform_device_register(&ath79_ehci_device); + ath79_usb_register("ehci-platform", -1, + AR933X_EHCI_BASE, AR933X_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); } static void __init ar934x_usb_setup(void) @@ -211,10 +202,10 @@ static void __init ar934x_usb_setup(void) ath79_device_reset_clear(AR934X_RESET_USB_HOST); udelay(1000); - ath79_usb_init_resource(ath79_ehci_resources, AR934X_EHCI_BASE, - AR934X_EHCI_SIZE, ATH79_CPU_IRQ(3)); - ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2; - platform_device_register(&ath79_ehci_device); + ath79_usb_register("ehci-platform", -1, + AR934X_EHCI_BASE, AR934X_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); } void __init ath79_register_usb(void) -- cgit v1.2.3-59-g8ed1b From d3ff9338023236f39332b07b3afed76c490a5041 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Feb 2013 19:41:47 +0000 Subject: mips: Make sure kernel memory is in iomem Kernel memory isn't necessarily added to the memory tables, so it wouldn't show up in /proc/iomem. This was breaking kdump, which requires these memory addresses to work correctly. Signed-off-by: Corey Minyard Acked-by: David Daney Cc: Ralf Baechle Patchwork: http://patchwork.linux-mips.org/patch/4937/ --- arch/mips/kernel/setup.c | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8c41187801ce..53462500c3cd 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -480,34 +480,44 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); -static void __init arch_mem_init(char **cmdline_p) +static void __init arch_mem_addpart(phys_t mem, phys_t end, int type) { - phys_t init_mem, init_end, init_size; + phys_t size; + int i; + + size = end - mem; + if (!size) + return; + + /* Make sure it is in the boot_mem_map */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (mem >= boot_mem_map.map[i].addr && + mem < (boot_mem_map.map[i].addr + + boot_mem_map.map[i].size)) + return; + } + add_memory_region(mem, size, type); +} +static void __init arch_mem_init(char **cmdline_p) +{ extern void plat_mem_setup(void); /* call board setup routine */ plat_mem_setup(); - init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT; - init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT; - init_size = init_end - init_mem; - if (init_size) { - /* Make sure it is in the boot_mem_map */ - int i, found; - found = 0; - for (i = 0; i < boot_mem_map.nr_map; i++) { - if (init_mem >= boot_mem_map.map[i].addr && - init_mem < (boot_mem_map.map[i].addr + - boot_mem_map.map[i].size)) { - found = 1; - break; - } - } - if (!found) - add_memory_region(init_mem, init_size, - BOOT_MEM_INIT_RAM); - } + /* + * Make sure all kernel memory is in the maps. The "UP" and + * "DOWN" are opposite for initdata since if it crosses over + * into another memory section you don't want that to be + * freed when the initdata is freed. + */ + arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT, + PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT, + BOOT_MEM_RAM); + arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT, + PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT, + BOOT_MEM_INIT_RAM); pr_info("Determined physical RAM map:\n"); print_memory_map(); -- cgit v1.2.3-59-g8ed1b From 4893fc8856a81d2037c1c976cb320be6f00e84a0 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 12 Feb 2013 19:41:48 +0000 Subject: mips: reserve elfcorehdr /proc/vmcore wasn't showing up in kdump kernels. It turns that that for Octeon, the memory used by elfcorehdr wasn't being set aside properly and it was getting clobbered before /proc/vmcore could get it. So reserve the memory if it shows up in a memory area managed by the kernel. Signed-off-by: Corey Minyard Acked-by: David Daney Cc: Ralf Baechle Patchwork: http://patchwork.linux-mips.org/patch/4936/ --- arch/mips/kernel/setup.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 53462500c3cd..795f4379c0b6 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -480,6 +480,37 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); +#ifdef CONFIG_PROC_VMCORE +unsigned long setup_elfcorehdr, setup_elfcorehdr_size; +static int __init early_parse_elfcorehdr(char *p) +{ + int i; + + setup_elfcorehdr = memparse(p, &p); + + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start = boot_mem_map.map[i].addr; + unsigned long end = (boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + if (setup_elfcorehdr >= start && setup_elfcorehdr < end) { + /* + * Reserve from the elf core header to the end of + * the memory segment, that should all be kdump + * reserved memory. + */ + setup_elfcorehdr_size = end - setup_elfcorehdr; + break; + } + } + /* + * If we don't find it in the memory map, then we shouldn't + * have to worry about it, as the new kernel won't use it. + */ + return 0; +} +early_param("elfcorehdr", early_parse_elfcorehdr); +#endif + static void __init arch_mem_addpart(phys_t mem, phys_t end, int type) { phys_t size; @@ -547,6 +578,14 @@ static void __init arch_mem_init(char **cmdline_p) } bootmem_init(); +#ifdef CONFIG_PROC_VMCORE + if (setup_elfcorehdr && setup_elfcorehdr_size) { + printk(KERN_INFO "kdump reserved memory at %lx-%lx\n", + setup_elfcorehdr, setup_elfcorehdr_size); + reserve_bootmem(setup_elfcorehdr, setup_elfcorehdr_size, + BOOTMEM_DEFAULT); + } +#endif #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) reserve_bootmem(crashk_res.start, -- cgit v1.2.3-59-g8ed1b From e3b25cead4b58fbf60270ba73a1669bf9e5635f5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 18:51:57 +0000 Subject: MIPS: ath79: fix WMAC IRQ resource assignment The '.start' field of the IRQ resource assigned twice in ar934x_wmac_setup(). The second assignment must set the '.end' field. Fix it. Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4954/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-wmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c index 4f6c4e389172..d71d745e3109 100644 --- a/arch/mips/ath79/dev-wmac.c +++ b/arch/mips/ath79/dev-wmac.c @@ -107,7 +107,7 @@ static void ar934x_wmac_setup(void) ath79_wmac_resources[0].start = AR934X_WMAC_BASE; ath79_wmac_resources[0].end = AR934X_WMAC_BASE + AR934X_WMAC_SIZE - 1; ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); - ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); + ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1); t = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); if (t & AR934X_BOOTSTRAP_REF_CLK_40) -- cgit v1.2.3-59-g8ed1b From 908987797076b848f01b32c21d61d0e152efc236 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:15 +0000 Subject: MIPS: ath79: add early printk support for the QCA955X SoCs The patch allows to see kernel messages on the QCA955X SoCs in early boot stage. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4944/ Signed-off-by: John Crispin --- arch/mips/ath79/early_printk.c | 2 ++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c index dc938cb2ba58..b955fafc58ba 100644 --- a/arch/mips/ath79/early_printk.c +++ b/arch/mips/ath79/early_printk.c @@ -74,6 +74,8 @@ static void prom_putchar_init(void) case REV_ID_MAJOR_AR9341: case REV_ID_MAJOR_AR9342: case REV_ID_MAJOR_AR9344: + case REV_ID_MAJOR_QCA9556: + case REV_ID_MAJOR_QCA9558: _prom_putchar = prom_putchar_ar71xx; break; diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index a77f6ee70ec1..d02c2d4e600e 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -370,6 +370,8 @@ #define REV_ID_MAJOR_AR9341 0x0120 #define REV_ID_MAJOR_AR9342 0x1120 #define REV_ID_MAJOR_AR9344 0x2120 +#define REV_ID_MAJOR_QCA9556 0x0130 +#define REV_ID_MAJOR_QCA9558 0x1130 #define AR71XX_REV_ID_MINOR_MASK 0x3 #define AR71XX_REV_ID_MINOR_AR7130 0x0 -- cgit v1.2.3-59-g8ed1b From 2e6c91e392fd7be2ef0ba1e9a20e0ebe8ab79cf3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:16 +0000 Subject: MIPS: ath79: add SoC detection code for the QCA955X SoCs Also add 'soc_is_qca955[68x]' helper functions and a Kconfig symbol for the SoC family. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4943/ Signed-off-by: John Crispin --- arch/mips/ath79/Kconfig | 4 ++++ arch/mips/ath79/setup.c | 18 +++++++++++++++++- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 2 ++ arch/mips/include/asm/mach-ath79/ath79.h | 17 +++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index f44feee2d67f..cffdc8e3b63b 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -88,6 +88,10 @@ config SOC_AR934X select PCI_AR724X if PCI def_bool n +config SOC_QCA955X + select USB_ARCH_HAS_EHCI + def_bool n + config PCI_AR724X def_bool n diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 60d212ef8629..d5b3c9057018 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -164,13 +164,29 @@ static void __init ath79_detect_sys_type(void) rev = id & AR934X_REV_ID_REVISION_MASK; break; + case REV_ID_MAJOR_QCA9556: + ath79_soc = ATH79_SOC_QCA9556; + chip = "9556"; + rev = id & QCA955X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_QCA9558: + ath79_soc = ATH79_SOC_QCA9558; + chip = "9558"; + rev = id & QCA955X_REV_ID_REVISION_MASK; + break; + default: panic("ath79: unknown SoC, id:0x%08x", id); } ath79_soc_rev = rev; - sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); + if (soc_is_qca955x()) + sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s rev %u", + chip, rev); + else + sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); pr_info("SoC: %s\n", ath79_sys_type); } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index d02c2d4e600e..63a9f2b600b8 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -392,6 +392,8 @@ #define AR934X_REV_ID_REVISION_MASK 0xf +#define QCA955X_REV_ID_REVISION_MASK 0xf + /* * SPI block */ diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h index 4f248c3d7b23..1557934aaca9 100644 --- a/arch/mips/include/asm/mach-ath79/ath79.h +++ b/arch/mips/include/asm/mach-ath79/ath79.h @@ -32,6 +32,8 @@ enum ath79_soc_type { ATH79_SOC_AR9341, ATH79_SOC_AR9342, ATH79_SOC_AR9344, + ATH79_SOC_QCA9556, + ATH79_SOC_QCA9558, }; extern enum ath79_soc_type ath79_soc; @@ -98,6 +100,21 @@ static inline int soc_is_ar934x(void) return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344(); } +static inline int soc_is_qca9556(void) +{ + return ath79_soc == ATH79_SOC_QCA9556; +} + +static inline int soc_is_qca9558(void) +{ + return ath79_soc == ATH79_SOC_QCA9558; +} + +static inline int soc_is_qca955x(void) +{ + return soc_is_qca9556() || soc_is_qca9558(); +} + extern void __iomem *ath79_ddr_base; extern void __iomem *ath79_pll_base; extern void __iomem *ath79_reset_base; -- cgit v1.2.3-59-g8ed1b From 41583c05c15cd3adb848f9ee8316bf8084c961cb Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:17 +0000 Subject: MIPS: ath79: add clock setup code for the QCA955X SoCs The patch adds code to get various clock frequencies from the PLLs used in the QCA955x SoCs. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4945/ Signed-off-by: John Crispin --- arch/mips/ath79/clock.c | 78 ++++++++++++++++++++++++++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 39 +++++++++++++ 2 files changed, 117 insertions(+) diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index 579f452c0b45..555e603de619 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -295,6 +295,82 @@ static void __init ar934x_clocks_init(void) iounmap(dpll_base); } +static void __init qca955x_clocks_init(void) +{ + u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; + u32 cpu_pll, ddr_pll; + u32 bootstrap; + + bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP); + if (bootstrap & QCA955X_BOOTSTRAP_REF_CLK_40) + ath79_ref_clk.rate = 40 * 1000 * 1000; + else + ath79_ref_clk.rate = 25 * 1000 * 1000; + + pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG); + out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & + QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK; + ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) & + QCA955X_PLL_CPU_CONFIG_REFDIV_MASK; + nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) & + QCA955X_PLL_CPU_CONFIG_NINT_MASK; + frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) & + QCA955X_PLL_CPU_CONFIG_NFRAC_MASK; + + cpu_pll = nint * ath79_ref_clk.rate / ref_div; + cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 6)); + cpu_pll /= (1 << out_div); + + pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG); + out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & + QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK; + ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) & + QCA955X_PLL_DDR_CONFIG_REFDIV_MASK; + nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) & + QCA955X_PLL_DDR_CONFIG_NINT_MASK; + frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) & + QCA955X_PLL_DDR_CONFIG_NFRAC_MASK; + + ddr_pll = nint * ath79_ref_clk.rate / ref_div; + ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 10)); + ddr_pll /= (1 << out_div); + + clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG); + + postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) & + QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK; + + if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS) + ath79_cpu_clk.rate = ath79_ref_clk.rate; + else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL) + ath79_cpu_clk.rate = ddr_pll / (postdiv + 1); + else + ath79_cpu_clk.rate = cpu_pll / (postdiv + 1); + + postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) & + QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK; + + if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS) + ath79_ddr_clk.rate = ath79_ref_clk.rate; + else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL) + ath79_ddr_clk.rate = cpu_pll / (postdiv + 1); + else + ath79_ddr_clk.rate = ddr_pll / (postdiv + 1); + + postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) & + QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK; + + if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS) + ath79_ahb_clk.rate = ath79_ref_clk.rate; + else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) + ath79_ahb_clk.rate = ddr_pll / (postdiv + 1); + else + ath79_ahb_clk.rate = cpu_pll / (postdiv + 1); + + ath79_wdt_clk.rate = ath79_ref_clk.rate; + ath79_uart_clk.rate = ath79_ref_clk.rate; +} + void __init ath79_clocks_init(void) { if (soc_is_ar71xx()) @@ -307,6 +383,8 @@ void __init ath79_clocks_init(void) ar933x_clocks_init(); else if (soc_is_ar934x()) ar934x_clocks_init(); + else if (soc_is_qca955x()) + qca955x_clocks_init(); else BUG(); diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 63a9f2b600b8..7b00e12afc1c 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -225,6 +225,41 @@ #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL BIT(21) #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL BIT(24) +#define QCA955X_PLL_CPU_CONFIG_REG 0x00 +#define QCA955X_PLL_DDR_CONFIG_REG 0x04 +#define QCA955X_PLL_CLK_CTRL_REG 0x08 + +#define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT 0 +#define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f +#define QCA955X_PLL_CPU_CONFIG_NINT_SHIFT 6 +#define QCA955X_PLL_CPU_CONFIG_NINT_MASK 0x3f +#define QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT 12 +#define QCA955X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f +#define QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT 19 +#define QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK 0x3 + +#define QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT 0 +#define QCA955X_PLL_DDR_CONFIG_NFRAC_MASK 0x3ff +#define QCA955X_PLL_DDR_CONFIG_NINT_SHIFT 10 +#define QCA955X_PLL_DDR_CONFIG_NINT_MASK 0x3f +#define QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT 16 +#define QCA955X_PLL_DDR_CONFIG_REFDIV_MASK 0x1f +#define QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT 23 +#define QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK 0x7 + +#define QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS BIT(2) +#define QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS BIT(3) +#define QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS BIT(4) +#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT 5 +#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK 0x1f +#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT 10 +#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK 0x1f +#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT 15 +#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK 0x1f +#define QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL BIT(20) +#define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL BIT(21) +#define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL BIT(24) + /* * USB_CONFIG block */ @@ -264,6 +299,8 @@ #define AR934X_RESET_REG_BOOTSTRAP 0xb0 #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac +#define QCA955X_RESET_REG_BOOTSTRAP 0xb0 + #define MISC_INT_ETHSW BIT(12) #define MISC_INT_TIMER4 BIT(10) #define MISC_INT_TIMER3 BIT(9) @@ -341,6 +378,8 @@ #define AR934X_BOOTSTRAP_SDRAM_DISABLED BIT(1) #define AR934X_BOOTSTRAP_DDR1 BIT(0) +#define QCA955X_BOOTSTRAP_REF_CLK_40 BIT(4) + #define AR934X_PCIE_WMAC_INT_WMAC_MISC BIT(0) #define AR934X_PCIE_WMAC_INT_WMAC_TX BIT(1) #define AR934X_PCIE_WMAC_INT_WMAC_RXLP BIT(2) -- cgit v1.2.3-59-g8ed1b From 53330332f176eaa9567481c69bbad8b2176b4eb5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 18:53:47 +0000 Subject: MIPS: ath79: add IRQ handling code for the QCA955X SoCs The IRQ routing in the QCA955x SoCs is slightly different from the routing implemented in the already supported SoCs. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4955/ Signed-off-by: John Crispin --- arch/mips/ath79/irq.c | 110 +++++++++++++++++++++++-- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 32 +++++++ arch/mips/include/asm/mach-ath79/irq.h | 6 +- 3 files changed, 140 insertions(+), 8 deletions(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index df88d49bcb05..9c0e1761773f 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -103,7 +103,10 @@ static void __init ath79_misc_irq_init(void) if (soc_is_ar71xx() || soc_is_ar913x()) ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; - else if (soc_is_ar724x() || soc_is_ar933x() || soc_is_ar934x()) + else if (soc_is_ar724x() || + soc_is_ar933x() || + soc_is_ar934x() || + soc_is_qca955x()) ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; else BUG(); @@ -150,6 +153,88 @@ static void ar934x_ip2_irq_init(void) irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch); } +static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + u32 status; + + disable_irq_nosync(irq); + + status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); + status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; + + if (status == 0) { + spurious_interrupt(); + goto enable; + } + + if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) { + /* TODO: flush DDR? */ + generic_handle_irq(ATH79_IP2_IRQ(0)); + } + + if (status & QCA955X_EXT_INT_WMAC_ALL) { + /* TODO: flush DDR? */ + generic_handle_irq(ATH79_IP2_IRQ(1)); + } + +enable: + enable_irq(irq); +} + +static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + u32 status; + + disable_irq_nosync(irq); + + status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); + status &= QCA955X_EXT_INT_PCIE_RC2_ALL | + QCA955X_EXT_INT_USB1 | + QCA955X_EXT_INT_USB2; + + if (status == 0) { + spurious_interrupt(); + goto enable; + } + + if (status & QCA955X_EXT_INT_USB1) { + /* TODO: flush DDR? */ + generic_handle_irq(ATH79_IP3_IRQ(0)); + } + + if (status & QCA955X_EXT_INT_USB2) { + /* TODO: flush DDR? */ + generic_handle_irq(ATH79_IP3_IRQ(1)); + } + + if (status & QCA955X_EXT_INT_PCIE_RC2_ALL) { + /* TODO: flush DDR? */ + generic_handle_irq(ATH79_IP3_IRQ(2)); + } + +enable: + enable_irq(irq); +} + +static void qca955x_irq_init(void) +{ + int i; + + for (i = ATH79_IP2_IRQ_BASE; + i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &dummy_irq_chip, + handle_level_irq); + + irq_set_chained_handler(ATH79_CPU_IRQ(2), qca955x_ip2_irq_dispatch); + + for (i = ATH79_IP3_IRQ_BASE; + i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &dummy_irq_chip, + handle_level_irq); + + irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch); +} + asmlinkage void plat_irq_dispatch(void) { unsigned long pending; @@ -185,6 +270,17 @@ asmlinkage void plat_irq_dispatch(void) * Issue a flush in the handlers to ensure that the driver sees * the update. */ + +static void ath79_default_ip2_handler(void) +{ + do_IRQ(ATH79_CPU_IRQ(2)); +} + +static void ath79_default_ip3_handler(void) +{ + do_IRQ(ATH79_CPU_IRQ(3)); +} + static void ar71xx_ip2_handler(void) { ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI); @@ -209,11 +305,6 @@ static void ar933x_ip2_handler(void) do_IRQ(ATH79_CPU_IRQ(2)); } -static void ar934x_ip2_handler(void) -{ - do_IRQ(ATH79_CPU_IRQ(2)); -} - static void ar71xx_ip3_handler(void) { ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); @@ -259,8 +350,11 @@ void __init arch_init_irq(void) ath79_ip2_handler = ar933x_ip2_handler; ath79_ip3_handler = ar933x_ip3_handler; } else if (soc_is_ar934x()) { - ath79_ip2_handler = ar934x_ip2_handler; + ath79_ip2_handler = ath79_default_ip2_handler; ath79_ip3_handler = ar934x_ip3_handler; + } else if (soc_is_qca955x()) { + ath79_ip2_handler = ath79_default_ip2_handler; + ath79_ip3_handler = ath79_default_ip3_handler; } else { BUG(); } @@ -271,4 +365,6 @@ void __init arch_init_irq(void) if (soc_is_ar934x()) ar934x_ip2_irq_init(); + else if (soc_is_qca955x()) + qca955x_irq_init(); } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 7b00e12afc1c..8782d8b097a3 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -300,6 +300,7 @@ #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac #define QCA955X_RESET_REG_BOOTSTRAP 0xb0 +#define QCA955X_RESET_REG_EXT_INT_STATUS 0xac #define MISC_INT_ETHSW BIT(12) #define MISC_INT_TIMER4 BIT(10) @@ -398,6 +399,37 @@ AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \ AR934X_PCIE_WMAC_INT_PCIE_RC3) +#define QCA955X_EXT_INT_WMAC_MISC BIT(0) +#define QCA955X_EXT_INT_WMAC_TX BIT(1) +#define QCA955X_EXT_INT_WMAC_RXLP BIT(2) +#define QCA955X_EXT_INT_WMAC_RXHP BIT(3) +#define QCA955X_EXT_INT_PCIE_RC1 BIT(4) +#define QCA955X_EXT_INT_PCIE_RC1_INT0 BIT(5) +#define QCA955X_EXT_INT_PCIE_RC1_INT1 BIT(6) +#define QCA955X_EXT_INT_PCIE_RC1_INT2 BIT(7) +#define QCA955X_EXT_INT_PCIE_RC1_INT3 BIT(8) +#define QCA955X_EXT_INT_PCIE_RC2 BIT(12) +#define QCA955X_EXT_INT_PCIE_RC2_INT0 BIT(13) +#define QCA955X_EXT_INT_PCIE_RC2_INT1 BIT(14) +#define QCA955X_EXT_INT_PCIE_RC2_INT2 BIT(15) +#define QCA955X_EXT_INT_PCIE_RC2_INT3 BIT(16) +#define QCA955X_EXT_INT_USB1 BIT(24) +#define QCA955X_EXT_INT_USB2 BIT(28) + +#define QCA955X_EXT_INT_WMAC_ALL \ + (QCA955X_EXT_INT_WMAC_MISC | QCA955X_EXT_INT_WMAC_TX | \ + QCA955X_EXT_INT_WMAC_RXLP | QCA955X_EXT_INT_WMAC_RXHP) + +#define QCA955X_EXT_INT_PCIE_RC1_ALL \ + (QCA955X_EXT_INT_PCIE_RC1 | QCA955X_EXT_INT_PCIE_RC1_INT0 | \ + QCA955X_EXT_INT_PCIE_RC1_INT1 | QCA955X_EXT_INT_PCIE_RC1_INT2 | \ + QCA955X_EXT_INT_PCIE_RC1_INT3) + +#define QCA955X_EXT_INT_PCIE_RC2_ALL \ + (QCA955X_EXT_INT_PCIE_RC2 | QCA955X_EXT_INT_PCIE_RC2_INT0 | \ + QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \ + QCA955X_EXT_INT_PCIE_RC2_INT3) + #define REV_ID_MAJOR_MASK 0xfff0 #define REV_ID_MAJOR_AR71XX 0x00a0 #define REV_ID_MAJOR_AR913X 0x00b0 diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h index 23e2bba42482..5c9ca76a7ebf 100644 --- a/arch/mips/include/asm/mach-ath79/irq.h +++ b/arch/mips/include/asm/mach-ath79/irq.h @@ -10,7 +10,7 @@ #define __ASM_MACH_ATH79_IRQ_H #define MIPS_CPU_IRQ_BASE 0 -#define NR_IRQS 48 +#define NR_IRQS 51 #define ATH79_CPU_IRQ(_x) (MIPS_CPU_IRQ_BASE + (_x)) @@ -26,6 +26,10 @@ #define ATH79_IP2_IRQ_COUNT 2 #define ATH79_IP2_IRQ(_x) (ATH79_IP2_IRQ_BASE + (_x)) +#define ATH79_IP3_IRQ_BASE (ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT) +#define ATH79_IP3_IRQ_COUNT 3 +#define ATH79_IP3_IRQ(_x) (ATH79_IP3_IRQ_BASE + (_x)) + #include_next #endif /* __ASM_MACH_ATH79_IRQ_H */ -- cgit v1.2.3-59-g8ed1b From f818ca3e6894d4a630a1ecc673c91df8fb6f6898 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:19 +0000 Subject: MIPS: ath79: add GPIO setup code for the QCA955X SoCs The existing code can handle the GPIO controller of the QCA955x SoCs. Add a minimal glue code to make it working. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4947/ Signed-off-by: John Crispin --- arch/mips/ath79/gpio.c | 4 +++- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index b7ed207e94a1..8d025b028bb1 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -194,12 +194,14 @@ void __init ath79_gpio_init(void) ath79_gpio_count = AR933X_GPIO_COUNT; else if (soc_is_ar934x()) ath79_gpio_count = AR934X_GPIO_COUNT; + else if (soc_is_qca955x()) + ath79_gpio_count = QCA955X_GPIO_COUNT; else BUG(); ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); ath79_gpio_chip.ngpio = ath79_gpio_count; - if (soc_is_ar934x()) { + if (soc_is_ar934x() || soc_is_qca955x()) { ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 8782d8b097a3..4868ed5c149b 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -510,6 +510,7 @@ #define AR913X_GPIO_COUNT 22 #define AR933X_GPIO_COUNT 30 #define AR934X_GPIO_COUNT 23 +#define QCA955X_GPIO_COUNT 24 /* * SRIF block -- cgit v1.2.3-59-g8ed1b From 7d4c2af9bdbbe789fe4a93f32c5890d72cbf60a1 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:20 +0000 Subject: MIPS: ath79: add QCA955X specific glue to ath79_device_reset_{set, clear} The ath79_device_reset_* are causing BUG when those are used on the QCA955x SoCs. The patch adds the required code to avoid that. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4948/ Signed-off-by: John Crispin --- arch/mips/ath79/common.c | 4 ++++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 1 + 2 files changed, 5 insertions(+) diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 5a4adfc9d79d..eb3966cd8cfc 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -72,6 +72,8 @@ void ath79_device_reset_set(u32 mask) reg = AR933X_RESET_REG_RESET_MODULE; else if (soc_is_ar934x()) reg = AR934X_RESET_REG_RESET_MODULE; + else if (soc_is_qca955x()) + reg = QCA955X_RESET_REG_RESET_MODULE; else BUG(); @@ -98,6 +100,8 @@ void ath79_device_reset_clear(u32 mask) reg = AR933X_RESET_REG_RESET_MODULE; else if (soc_is_ar934x()) reg = AR934X_RESET_REG_RESET_MODULE; + else if (soc_is_qca955x()) + reg = QCA955X_RESET_REG_RESET_MODULE; else BUG(); diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 4868ed5c149b..bf50ddfc9d5c 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -299,6 +299,7 @@ #define AR934X_RESET_REG_BOOTSTRAP 0xb0 #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac +#define QCA955X_RESET_REG_RESET_MODULE 0x1c #define QCA955X_RESET_REG_BOOTSTRAP 0xb0 #define QCA955X_RESET_REG_EXT_INT_STATUS 0xac -- cgit v1.2.3-59-g8ed1b From 13992303fa705ae1e4acf4660c69687672996029 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:21 +0000 Subject: MIPS: ath79: register UART for the QCA955X SoCs Similarly to the preceding SoCs, the QCA955X SoCs also have a built-in NS16650 compatible UART. Register the platform device for that to make it usable. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4949/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c index 480f5eb9d300..9516aab27139 100644 --- a/arch/mips/ath79/dev-common.c +++ b/arch/mips/ath79/dev-common.c @@ -90,7 +90,8 @@ void __init ath79_register_uart(void) if (soc_is_ar71xx() || soc_is_ar724x() || soc_is_ar913x() || - soc_is_ar934x()) { + soc_is_ar934x() || + soc_is_qca955x()) { ath79_uart_data[0].uartclk = clk_get_rate(clk); platform_device_register(&ath79_uart_device); } else if (soc_is_ar933x()) { -- cgit v1.2.3-59-g8ed1b From e9c0d0aaa3a7a6e66135e8b44f3323143a635098 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 18:54:33 +0000 Subject: MIPS: ath79: add WMAC registration code for the QCA955X SoCs The SoC has a built-in wireless MAC. Register a platform device for that to make it usable with the ath9k driver. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4956/ Signed-off-by: John Crispin --- arch/mips/ath79/Kconfig | 2 +- arch/mips/ath79/dev-wmac.c | 20 ++++++++++++++++++++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 3 +++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index cffdc8e3b63b..77926e331b17 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -108,7 +108,7 @@ config ATH79_DEV_USB def_bool n config ATH79_DEV_WMAC - depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X) + depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X) def_bool n endif diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c index d71d745e3109..da190b1b87ce 100644 --- a/arch/mips/ath79/dev-wmac.c +++ b/arch/mips/ath79/dev-wmac.c @@ -116,6 +116,24 @@ static void ar934x_wmac_setup(void) ath79_wmac_data.is_clk_25mhz = true; } +static void qca955x_wmac_setup(void) +{ + u32 t; + + ath79_wmac_device.name = "qca955x_wmac"; + + ath79_wmac_resources[0].start = QCA955X_WMAC_BASE; + ath79_wmac_resources[0].end = QCA955X_WMAC_BASE + QCA955X_WMAC_SIZE - 1; + ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); + ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1); + + t = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP); + if (t & QCA955X_BOOTSTRAP_REF_CLK_40) + ath79_wmac_data.is_clk_25mhz = false; + else + ath79_wmac_data.is_clk_25mhz = true; +} + void __init ath79_register_wmac(u8 *cal_data) { if (soc_is_ar913x()) @@ -124,6 +142,8 @@ void __init ath79_register_wmac(u8 *cal_data) ar933x_wmac_setup(); else if (soc_is_ar934x()) ar934x_wmac_setup(); + else if (soc_is_qca955x()) + qca955x_wmac_setup(); else BUG(); diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index bf50ddfc9d5c..47282120db1e 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -94,6 +94,9 @@ #define AR934X_SRIF_BASE (AR71XX_APB_BASE + 0x00116000) #define AR934X_SRIF_SIZE 0x1000 +#define QCA955X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) +#define QCA955X_WMAC_SIZE 0x20000 + /* * DDR_CTRL block */ -- cgit v1.2.3-59-g8ed1b From 0a5f3b1c9f20eb44142e3b37662de15c944f759d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:23 +0000 Subject: MIPS: ath79: add PCI controller registration code for the QCA955X SoCs Add SoC specific PCI IRQ map, and register platform devices for the two built-in PCIe RCs. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4951/ Signed-off-by: John Crispin --- arch/mips/ath79/Kconfig | 2 ++ arch/mips/ath79/pci.c | 36 ++++++++++++++++++++++++++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 13 ++++++++++ 3 files changed, 51 insertions(+) diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 77926e331b17..76a001e5fc26 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -90,6 +90,8 @@ config SOC_AR934X config SOC_QCA955X select USB_ARCH_HAS_EHCI + select HW_HAS_PCI + select PCI_AR724X if PCI def_bool n config PCI_AR724X diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index 4350c252bce5..730c0b03060d 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c @@ -49,6 +49,21 @@ static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = { } }; +static const struct ath79_pci_irq qca955x_pci_irq_map[] __initconst = { + { + .bus = 0, + .slot = 0, + .pin = 1, + .irq = ATH79_PCI_IRQ(0), + }, + { + .bus = 1, + .slot = 0, + .pin = 1, + .irq = ATH79_PCI_IRQ(1), + }, +}; + int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) { int irq = -1; @@ -64,6 +79,9 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) soc_is_ar9344()) { ath79_pci_irq_map = ar724x_pci_irq_map; ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map); + } else if (soc_is_qca955x()) { + ath79_pci_irq_map = qca955x_pci_irq_map; + ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map); } else { pr_crit("pci %s: invalid irq map\n", pci_name((struct pci_dev *) dev)); @@ -225,6 +243,24 @@ int __init ath79_register_pci(void) AR724X_PCI_MEM_SIZE, 0, ATH79_IP2_IRQ(0)); + } else if (soc_is_qca9558()) { + pdev = ath79_register_pci_ar724x(0, + QCA955X_PCI_CFG_BASE0, + QCA955X_PCI_CTRL_BASE0, + QCA955X_PCI_CRP_BASE0, + QCA955X_PCI_MEM_BASE0, + QCA955X_PCI_MEM_SIZE, + 0, + ATH79_IP2_IRQ(0)); + + pdev = ath79_register_pci_ar724x(1, + QCA955X_PCI_CFG_BASE1, + QCA955X_PCI_CTRL_BASE1, + QCA955X_PCI_CRP_BASE1, + QCA955X_PCI_MEM_BASE1, + QCA955X_PCI_MEM_SIZE, + 1, + ATH79_IP3_IRQ(2)); } else { /* No PCI support */ return -ENODEV; diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 47282120db1e..b7fa9d14d20f 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -94,6 +94,19 @@ #define AR934X_SRIF_BASE (AR71XX_APB_BASE + 0x00116000) #define AR934X_SRIF_SIZE 0x1000 +#define QCA955X_PCI_MEM_BASE0 0x10000000 +#define QCA955X_PCI_MEM_BASE1 0x12000000 +#define QCA955X_PCI_MEM_SIZE 0x02000000 +#define QCA955X_PCI_CFG_BASE0 0x14000000 +#define QCA955X_PCI_CFG_BASE1 0x16000000 +#define QCA955X_PCI_CFG_SIZE 0x1000 +#define QCA955X_PCI_CRP_BASE0 (AR71XX_APB_BASE + 0x000c0000) +#define QCA955X_PCI_CRP_BASE1 (AR71XX_APB_BASE + 0x00250000) +#define QCA955X_PCI_CRP_SIZE 0x1000 +#define QCA955X_PCI_CTRL_BASE0 (AR71XX_APB_BASE + 0x000f0000) +#define QCA955X_PCI_CTRL_BASE1 (AR71XX_APB_BASE + 0x00280000) +#define QCA955X_PCI_CTRL_SIZE 0x100 + #define QCA955X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) #define QCA955X_WMAC_SIZE 0x20000 -- cgit v1.2.3-59-g8ed1b From 82c46840ae6bd8a147c59cd51f636d913989324a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:24 +0000 Subject: MIPS: ath79: add USB controller registration code for the QCA955X SoCs Register platfom devices for the built-in USB controllers of the SoCs. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4952/ Signed-off-by: John Crispin --- arch/mips/ath79/dev-usb.c | 15 +++++++++++++++ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index 02124d02cf6e..8227265bcc2d 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -208,6 +208,19 @@ static void __init ar934x_usb_setup(void) &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); } +static void __init qca955x_usb_setup(void) +{ + ath79_usb_register("ehci-platform", 0, + QCA955X_EHCI0_BASE, QCA955X_EHCI_SIZE, + ATH79_IP3_IRQ(0), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); + + ath79_usb_register("ehci-platform", 1, + QCA955X_EHCI1_BASE, QCA955X_EHCI_SIZE, + ATH79_IP3_IRQ(1), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); +} + void __init ath79_register_usb(void) { if (soc_is_ar71xx()) @@ -222,6 +235,8 @@ void __init ath79_register_usb(void) ar933x_usb_setup(); else if (soc_is_ar934x()) ar934x_usb_setup(); + else if (soc_is_qca955x()) + qca955x_usb_setup(); else BUG(); } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index b7fa9d14d20f..4de183112917 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -109,6 +109,9 @@ #define QCA955X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) #define QCA955X_WMAC_SIZE 0x20000 +#define QCA955X_EHCI0_BASE 0x1b000000 +#define QCA955X_EHCI1_BASE 0x1b400000 +#define QCA955X_EHCI_SIZE 0x1000 /* * DDR_CTRL block -- cgit v1.2.3-59-g8ed1b From 27ea052acb9eaca98cc90bf1b8738b6d0ea5bc2f Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 15 Feb 2013 13:38:25 +0000 Subject: MIPS: ath79: add support for the Qualcomm Atheros AP136-010 board Also enable the board in the default configuration. Cc: Rodriguez, Luis Cc: Giori, Kathy Cc: QCA Linux Team Signed-off-by: Gabor Juhos Patchwork: http://patchwork.linux-mips.org/patch/4953/ Signed-off-by: John Crispin --- arch/mips/ath79/Kconfig | 12 +++ arch/mips/ath79/Makefile | 1 + arch/mips/ath79/mach-ap136.c | 156 ++++++++++++++++++++++++++++++++++++++ arch/mips/ath79/machtypes.h | 1 + arch/mips/configs/ath79_defconfig | 1 + 5 files changed, 171 insertions(+) create mode 100644 arch/mips/ath79/mach-ap136.c diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 76a001e5fc26..3995e31a73e2 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -14,6 +14,18 @@ config ATH79_MACH_AP121 Say 'Y' here if you want your kernel to support the Atheros AP121 reference board. +config ATH79_MACH_AP136 + bool "Atheros AP136 reference board" + select SOC_QCA955X + select ATH79_DEV_GPIO_BUTTONS + select ATH79_DEV_LEDS_GPIO + select ATH79_DEV_SPI + select ATH79_DEV_USB + select ATH79_DEV_WMAC + help + Say 'Y' here if you want your kernel to support the + Atheros AP136 reference board. + config ATH79_MACH_AP81 bool "Atheros AP81 reference board" select SOC_AR913X diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile index 2b54d98263f3..5c9ff692ff3c 100644 --- a/arch/mips/ath79/Makefile +++ b/arch/mips/ath79/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ATH79_DEV_WMAC) += dev-wmac.o # Machines # obj-$(CONFIG_ATH79_MACH_AP121) += mach-ap121.o +obj-$(CONFIG_ATH79_MACH_AP136) += mach-ap136.o obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o obj-$(CONFIG_ATH79_MACH_DB120) += mach-db120.o obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o diff --git a/arch/mips/ath79/mach-ap136.c b/arch/mips/ath79/mach-ap136.c new file mode 100644 index 000000000000..479dd4b1d0d2 --- /dev/null +++ b/arch/mips/ath79/mach-ap136.c @@ -0,0 +1,156 @@ +/* + * Qualcomm Atheros AP136 reference board support + * + * Copyright (c) 2012 Qualcomm Atheros + * Copyright (c) 2012-2013 Gabor Juhos + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include + +#include "machtypes.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-spi.h" +#include "dev-usb.h" +#include "dev-wmac.h" +#include "pci.h" + +#define AP136_GPIO_LED_STATUS_RED 14 +#define AP136_GPIO_LED_STATUS_GREEN 19 +#define AP136_GPIO_LED_USB 4 +#define AP136_GPIO_LED_WLAN_2G 13 +#define AP136_GPIO_LED_WLAN_5G 12 +#define AP136_GPIO_LED_WPS_RED 15 +#define AP136_GPIO_LED_WPS_GREEN 20 + +#define AP136_GPIO_BTN_WPS 16 +#define AP136_GPIO_BTN_RFKILL 21 + +#define AP136_KEYS_POLL_INTERVAL 20 /* msecs */ +#define AP136_KEYS_DEBOUNCE_INTERVAL (3 * AP136_KEYS_POLL_INTERVAL) + +#define AP136_WMAC_CALDATA_OFFSET 0x1000 +#define AP136_PCIE_CALDATA_OFFSET 0x5000 + +static struct gpio_led ap136_leds_gpio[] __initdata = { + { + .name = "qca:green:status", + .gpio = AP136_GPIO_LED_STATUS_GREEN, + .active_low = 1, + }, + { + .name = "qca:red:status", + .gpio = AP136_GPIO_LED_STATUS_RED, + .active_low = 1, + }, + { + .name = "qca:green:wps", + .gpio = AP136_GPIO_LED_WPS_GREEN, + .active_low = 1, + }, + { + .name = "qca:red:wps", + .gpio = AP136_GPIO_LED_WPS_RED, + .active_low = 1, + }, + { + .name = "qca:red:wlan-2g", + .gpio = AP136_GPIO_LED_WLAN_2G, + .active_low = 1, + }, + { + .name = "qca:red:usb", + .gpio = AP136_GPIO_LED_USB, + .active_low = 1, + } +}; + +static struct gpio_keys_button ap136_gpio_keys[] __initdata = { + { + .desc = "WPS button", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, + .debounce_interval = AP136_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP136_GPIO_BTN_WPS, + .active_low = 1, + }, + { + .desc = "RFKILL button", + .type = EV_KEY, + .code = KEY_RFKILL, + .debounce_interval = AP136_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP136_GPIO_BTN_RFKILL, + .active_low = 1, + }, +}; + +static struct spi_board_info ap136_spi_info[] = { + { + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 25000000, + .modalias = "mx25l6405d", + } +}; + +static struct ath79_spi_platform_data ap136_spi_data = { + .bus_num = 0, + .num_chipselect = 1, +}; + +#ifdef CONFIG_PCI +static struct ath9k_platform_data ap136_ath9k_data; + +static int ap136_pci_plat_dev_init(struct pci_dev *dev) +{ + if (dev->bus->number == 1 && (PCI_SLOT(dev->devfn)) == 0) + dev->dev.platform_data = &ap136_ath9k_data; + + return 0; +} + +static void __init ap136_pci_init(u8 *eeprom) +{ + memcpy(ap136_ath9k_data.eeprom_data, eeprom, + sizeof(ap136_ath9k_data.eeprom_data)); + + ath79_pci_set_plat_dev_init(ap136_pci_plat_dev_init); + ath79_register_pci(); +} +#else +static inline void ap136_pci_init(void) {} +#endif /* CONFIG_PCI */ + +static void __init ap136_setup(void) +{ + u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); + + ath79_register_leds_gpio(-1, ARRAY_SIZE(ap136_leds_gpio), + ap136_leds_gpio); + ath79_register_gpio_keys_polled(-1, AP136_KEYS_POLL_INTERVAL, + ARRAY_SIZE(ap136_gpio_keys), + ap136_gpio_keys); + ath79_register_spi(&ap136_spi_data, ap136_spi_info, + ARRAY_SIZE(ap136_spi_info)); + ath79_register_usb(); + ath79_register_wmac(art + AP136_WMAC_CALDATA_OFFSET); + ap136_pci_init(art + AP136_PCIE_CALDATA_OFFSET); +} + +MIPS_MACHINE(ATH79_MACH_AP136_010, "AP136-010", + "Atheros AP136-010 reference board", + ap136_setup); diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h index af92e5c30d66..26254058c545 100644 --- a/arch/mips/ath79/machtypes.h +++ b/arch/mips/ath79/machtypes.h @@ -17,6 +17,7 @@ enum ath79_mach_type { ATH79_MACH_GENERIC = 0, ATH79_MACH_AP121, /* Atheros AP121 reference board */ + ATH79_MACH_AP136_010, /* Atheros AP136-010 reference board */ ATH79_MACH_AP81, /* Atheros AP81 reference board */ ATH79_MACH_DB120, /* Atheros DB120 reference board */ ATH79_MACH_PB44, /* Atheros PB44 reference board */ diff --git a/arch/mips/configs/ath79_defconfig b/arch/mips/configs/ath79_defconfig index ea87d43ba607..e3a3836508ec 100644 --- a/arch/mips/configs/ath79_defconfig +++ b/arch/mips/configs/ath79_defconfig @@ -1,5 +1,6 @@ CONFIG_ATH79=y CONFIG_ATH79_MACH_AP121=y +CONFIG_ATH79_MACH_AP136=y CONFIG_ATH79_MACH_AP81=y CONFIG_ATH79_MACH_DB120=y CONFIG_ATH79_MACH_PB44=y -- cgit v1.2.3-59-g8ed1b From 1e7decdb27ae89b2a0626635a8cf527f930bff1c Mon Sep 17 00:00:00 2001 From: David Daney Date: Sat, 16 Feb 2013 23:42:43 +0100 Subject: MIPS: Probe for and report hardware virtualization support. The presence of the MIPS Virtualization Application-Specific Extension is indicated by CP0_Config3[23]. Probe for this and report it in /proc/cpuinfo. Signed-off-by: David Daney Patchwork: http://patchwork.linux-mips.org/patch/4904/ Signed-off-by: John Crispin --- arch/mips/include/asm/cpu-features.h | 4 ++++ arch/mips/include/asm/cpu.h | 2 +- arch/mips/include/asm/mipsregs.h | 1 + arch/mips/kernel/cpu-probe.c | 2 ++ arch/mips/kernel/proc.c | 1 + 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index 00171cddb6d5..c6f64ef0681e 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -263,4 +263,8 @@ #define cpu_has_perf_cntr_intr_bit (cpu_data[0].options & MIPS_CPU_PCI) #endif +#ifndef cpu_has_vz +#define cpu_has_vz (cpu_data[0].ases & MIPS_ASE_VZ) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 2de2fee16cc4..4dff3378d96f 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -336,6 +336,6 @@ enum cpu_type_enum { #define MIPS_ASE_DSP 0x00000010 /* Signal Processing ASE */ #define MIPS_ASE_MIPSMT 0x00000020 /* CPU supports MIPS MT */ #define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */ - +#define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */ #endif /* _ASM_CPU_H */ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 9f47cda632ab..5df4cda4991a 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -596,6 +596,7 @@ #define MIPS_CONF3_RXI (_ULCAST_(1) << 12) #define MIPS_CONF3_ULRI (_ULCAST_(1) << 13) #define MIPS_CONF3_ISA (_ULCAST_(3) << 14) +#define MIPS_CONF3_VZ (_ULCAST_(1) << 23) #define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0) #define MIPS_CONF4_MMUEXTDEF (_ULCAST_(3) << 14) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index ba169022fe1d..0c69d1d14080 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -442,6 +442,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_ULRI; if (config3 & MIPS_CONF3_ISA) c->options |= MIPS_CPU_MICROMIPS; + if (config3 & MIPS_CONF3_VZ) + c->ases |= MIPS_ASE_VZ; return config3 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 239ae03f3330..453d55699fef 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -74,6 +74,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_dsp2) seq_printf(m, "%s", " dsp2"); if (cpu_has_mipsmt) seq_printf(m, "%s", " mt"); if (cpu_has_mmips) seq_printf(m, "%s", " micromips"); + if (cpu_has_vz) seq_printf(m, "%s", " vz"); seq_printf(m, "\n"); seq_printf(m, "shadow register sets\t: %d\n", -- cgit v1.2.3-59-g8ed1b From f7be4e754b61681467f873400cbaa42a013b8973 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 11 Feb 2013 20:51:49 +0000 Subject: MIPS: early_printk: drop __init annotations We cannot use __init for earlyprintk code or data, since the kernel parameter "keep_bootcon" allows leaving the boot console enabled. Currently MIPS will crash/hang/die if you use keep_bootcon. The patch fixes it at least on Lemote FuLoong mini-PC. Changes for other boards were done based on what I could find with grep... Signed-off-by: Aaro Koskinen Patchwork: http://patchwork.linux-mips.org/patch/4935/ Signed-off-by: John Crispin --- arch/mips/bcm63xx/early_printk.c | 4 ++-- arch/mips/kernel/early_printk.c | 5 ++--- arch/mips/loongson1/common/prom.c | 2 +- arch/mips/sgi-ip27/ip27-console.c | 2 +- arch/mips/txx9/generic/setup.c | 8 ++++---- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/mips/bcm63xx/early_printk.c b/arch/mips/bcm63xx/early_printk.c index bf353c937df2..aa8f7f9cc7a4 100644 --- a/arch/mips/bcm63xx/early_printk.c +++ b/arch/mips/bcm63xx/early_printk.c @@ -10,7 +10,7 @@ #include #include -static void __init wait_xfered(void) +static void wait_xfered(void) { unsigned int val; @@ -22,7 +22,7 @@ static void __init wait_xfered(void) } while (1); } -void __init prom_putchar(char c) +void prom_putchar(char c) { wait_xfered(); bcm_uart0_writel(c, UART_FIFO_REG); diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c index 9ae813eb782e..9e6440eaa455 100644 --- a/arch/mips/kernel/early_printk.c +++ b/arch/mips/kernel/early_printk.c @@ -14,8 +14,7 @@ extern void prom_putchar(char); -static void __init -early_console_write(struct console *con, const char *s, unsigned n) +static void early_console_write(struct console *con, const char *s, unsigned n) { while (n-- && *s) { if (*s == '\n') @@ -25,7 +24,7 @@ early_console_write(struct console *con, const char *s, unsigned n) } } -static struct console early_console __initdata = { +static struct console early_console = { .name = "early", .write = early_console_write, .flags = CON_PRINTBUFFER | CON_BOOT, diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c index 1f8e49f9886d..54dee09b36cd 100644 --- a/arch/mips/loongson1/common/prom.c +++ b/arch/mips/loongson1/common/prom.c @@ -73,7 +73,7 @@ void __init prom_free_prom_memory(void) #define PORT(offset) (u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset)) -void __init prom_putchar(char c) +void prom_putchar(char c) { int timeout; diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c index 984e561f0f7a..b952d5b1af86 100644 --- a/arch/mips/sgi-ip27/ip27-console.c +++ b/arch/mips/sgi-ip27/ip27-console.c @@ -31,7 +31,7 @@ static inline struct ioc3_uartregs *console_uart(void) return &ioc3->sregs.uarta; } -void __init prom_putchar(char c) +void prom_putchar(char c) { struct ioc3_uartregs *uart = console_uart(); diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 560fe8991753..5524f2c7b05c 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -513,19 +513,19 @@ void __init txx9_sio_init(unsigned long baseaddr, int irq, } #ifdef CONFIG_EARLY_PRINTK -static void __init null_prom_putchar(char c) +static void null_prom_putchar(char c) { } -void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar; +void (*txx9_prom_putchar)(char c) = null_prom_putchar; -void __init prom_putchar(char c) +void prom_putchar(char c) { txx9_prom_putchar(c); } static void __iomem *early_txx9_sio_port; -static void __init early_txx9_sio_putchar(char c) +static void early_txx9_sio_putchar(char c) { #define TXX9_SICISR 0x0c #define TXX9_SITFIFO 0x1c -- cgit v1.2.3-59-g8ed1b From df1cc3da2134bc10e6edc62709013a10e03e4106 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 8 Feb 2013 09:45:14 +0000 Subject: MIPS: SMTC: fix implicit declaration of set_vi_handler This patch fixes the following implicit declaration while building with MIPS SMTC support enabled: arch/mips/kernel/smtc.c: In function 'setup_cross_vpe_interrupts': arch/mips/kernel/smtc.c:1205:2: error: implicit declaration of function 'set_vi_handler' [-Werror=implicit-function-declaration] cc1: all warnings being treated as errors Signed-off-by: Florian Fainelli Patchwork: http://patchwork.linux-mips.org/patch/4931/ Signed-off-by: John Crispin --- arch/mips/kernel/smtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 1d47843d3cc0..0822232b62fc 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * SMTC Kernel needs to manipulate low-level CPU interrupt mask -- cgit v1.2.3-59-g8ed1b From 535237cecab2b078114be712c67e89a0db61965f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 17 Feb 2013 01:16:15 +0100 Subject: MIPS: remove broken conditional inside vpe loader code The commit [1] breaks builds and results in the following error arch/mips/kernel/vpe.c: In function 'vpe_run': arch/mips/kernel/vpe.c:708:16: error: invalid type argument of '->' (have 'struct list_head') Taking a closer look at the conditional we notice that list_first_entry wont ever return NULL. The easiest fix is to just drop the dead code. [1] commit 3d2d03247632920aa21b42a0b032a4ffd44ce15e MIPS: vpe.c: Fix null pointer dereference in print arguments. Signed-off-by: John Crispin --- arch/mips/kernel/vpe.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 147cec19621d..0e0fdb783b7c 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -697,18 +697,7 @@ static int vpe_run(struct vpe * v) dmt_flag = dmt(); vpeflags = dvpe(); - if (!list_empty(&v->tc)) { - if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { - evpe(vpeflags); - emt(dmt_flag); - local_irq_restore(flags); - - printk(KERN_WARNING - "VPE loader: TC %d is already in use.\n", - v->tc->index); - return -ENOEXEC; - } - } else { + if (list_empty(&v->tc)) { evpe(vpeflags); emt(dmt_flag); local_irq_restore(flags); @@ -720,6 +709,8 @@ static int vpe_run(struct vpe * v) return -ENOEXEC; } + t = list_first_entry(&v->tc, struct tc, tc); + /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); -- cgit v1.2.3-59-g8ed1b