From 9839a5accde45f431cc1faf252e3973501b96298 Mon Sep 17 00:00:00 2001 From: Dennis Groenen Date: Tue, 11 Jan 2011 15:19:12 +0100 Subject: [PATCH] bfs 350 -> 357, kernel-power v41 -> kernel-bfs --- kernel-bfs-2.6.28/debian/changelog | 7 + .../debian/patches/bfs-350-to-357.patch | 237 ++++ .../debian/patches/mmcnames-fanoush.diff | 2 +- .../debian/patches/nokia-20103103+0m5.diff | 1439 ++++++++++++++++++++ kernel-bfs-2.6.28/debian/patches/series | 8 +- .../debian/patches/strip_cfs_nokia_pr13.diff | 78 ++ kernel-bfs-2.6.28/debian/patches/wl12xx_rohar.diff | 14 + kernel-bfs-2.6.28/debian/rules | 3 +- kernel-bfs-2.6.28/debian/rx51power_defconfig | 11 +- 9 files changed, 1790 insertions(+), 9 deletions(-) create mode 100644 kernel-bfs-2.6.28/debian/patches/bfs-350-to-357.patch create mode 100644 kernel-bfs-2.6.28/debian/patches/nokia-20103103+0m5.diff create mode 100644 kernel-bfs-2.6.28/debian/patches/strip_cfs_nokia_pr13.diff create mode 100644 kernel-bfs-2.6.28/debian/patches/wl12xx_rohar.diff diff --git a/kernel-bfs-2.6.28/debian/changelog b/kernel-bfs-2.6.28/debian/changelog index 1e70d2e..5484184 100644 --- a/kernel-bfs-2.6.28/debian/changelog +++ b/kernel-bfs-2.6.28/debian/changelog @@ -1,3 +1,10 @@ +kernel-bfs (2.6.28-bfs2) fremantle; urgency=low + + * Added kernel-power 2.6.28-maemo41 changes to kernel-bfs + * Updated BFS scheduler to bfs357 + + -- Dennis Groenen Tue, 09 Nov 2010 10:38:00 +0100 + kernel-bfs (2.6.28-bfs1) fremantle; urgency=low * Rename to avoid collision with kernel-power diff --git a/kernel-bfs-2.6.28/debian/patches/bfs-350-to-357.patch b/kernel-bfs-2.6.28/debian/patches/bfs-350-to-357.patch new file mode 100644 index 0000000..fc4c2a7 --- /dev/null +++ b/kernel-bfs-2.6.28/debian/patches/bfs-350-to-357.patch @@ -0,0 +1,237 @@ +I forgot about an awful lot of longs and ints that will overflow on 32 bit now +with u64 deadlines. Fix them. + +Add some macro tidiness. + +Make sched_clock sanity checking robust and standardised, using jiffy +difference as upper limit, and use nominal 1us when difference cannot be +trusted. + +Go magnum. + +-ck + +--- + include/linux/sched.h | 2 - + kernel/sched_bfs.c | 76 +++++++++++++++++++++++++++----------------------- + 2 files changed, 43 insertions(+), 35 deletions(-) + +Index: linux-2.6.35.7/kernel/sched_bfs.c +=================================================================== +--- linux-2.6.35.7.orig/kernel/sched_bfs.c 2010-10-03 21:29:08.421363441 +1100 ++++ linux-2.6.35.7/kernel/sched_bfs.c 2010-10-04 11:39:08.027283891 +1100 +@@ -111,10 +111,12 @@ + * approximate multiples of ten for less overhead. + */ + #define JIFFIES_TO_NS(TIME) ((TIME) * (1000000000 / HZ)) ++#define JIFFY_NS (1000000000 / HZ) + #define HALF_JIFFY_NS (1000000000 / HZ / 2) + #define HALF_JIFFY_US (1000000 / HZ / 2) + #define MS_TO_NS(TIME) ((TIME) << 20) + #define MS_TO_US(TIME) ((TIME) << 10) ++#define US_TO_NS(TIME) ((TIME) >> 10) + #define NS_TO_MS(TIME) ((TIME) >> 20) + #define NS_TO_US(TIME) ((TIME) >> 10) + +@@ -165,8 +167,8 @@ struct global_rq { + cpumask_t cpu_idle_map; + int idle_cpus; + #endif +- /* Nanosecond jiffies */ +- u64 niffies; ++ u64 niffies; /* Nanosecond jiffies */ ++ unsigned long last_jiffy; /* Last jiffy we updated niffies */ + + raw_spinlock_t iso_lock; + int iso_ticks; +@@ -193,7 +195,7 @@ struct rq { + struct mm_struct *prev_mm; + + /* Stored data about rq->curr to work outside grq lock */ +- unsigned long rq_deadline; ++ u64 rq_deadline; + unsigned int rq_policy; + int rq_time_slice; + u64 rq_last_ran; +@@ -315,6 +317,23 @@ static struct root_domain def_root_domai + + static inline void update_rq_clock(struct rq *rq); + ++/* ++ * Sanity check should sched_clock return bogus values. We make sure it does ++ * not appear to go backwards, and use jiffies to determine the maximum it ++ * could possibly have increased. At least 1us will have always passed so we ++ * use that when we don't trust the difference. ++ */ ++static inline void niffy_diff(s64 *niff_diff, int jiff_diff) ++{ ++ unsigned long max_diff; ++ ++ /* Round up to the nearest tick for maximum */ ++ max_diff = JIFFIES_TO_NS(jiff_diff + 1); ++ ++ if (unlikely(*niff_diff < 1 || *niff_diff > max_diff)) ++ *niff_diff = US_TO_NS(1); ++} ++ + #ifdef CONFIG_SMP + #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) + #define this_rq() (&__get_cpu_var(runqueues)) +@@ -335,18 +354,16 @@ static inline int cpu_of(struct rq *rq) + static inline void update_clocks(struct rq *rq) + { + s64 ndiff; ++ long jdiff; + + update_rq_clock(rq); + ndiff = rq->clock - rq->old_clock; + /* old_clock is only updated when we are updating niffies */ + rq->old_clock = rq->clock; + ndiff -= grq.niffies - rq->last_niffy; +- /* +- * Sanity check should sched_clock return bogus values or be limited to +- * just jiffy resolution. Some time will always have passed. +- */ +- if (unlikely(ndiff < 1 || ndiff > MS_TO_NS(rr_interval))) +- ndiff = 1; ++ jdiff = jiffies - grq.last_jiffy; ++ niffy_diff(&ndiff, jdiff); ++ grq.last_jiffy += jdiff; + grq.niffies += ndiff; + rq->last_niffy = grq.niffies; + } +@@ -364,12 +381,14 @@ static inline int cpu_of(struct rq *rq) + static inline void update_clocks(struct rq *rq) + { + s64 ndiff; ++ long jdiff; + + update_rq_clock(rq); + ndiff = rq->clock - rq->old_clock; + rq->old_clock = rq->clock; +- if (unlikely(ndiff < 1 || ndiff > MS_TO_US(rr_interval))) +- ndiff = 1; ++ jdiff = jiffies - grq.last_jiffy; ++ niffy_diff(&ndiff, jdiff); ++ grq.last_jiffy += jdiff; + grq.niffies += ndiff; + } + #endif +@@ -1202,7 +1221,7 @@ EXPORT_SYMBOL_GPL(kick_process); + * prio PRIO_LIMIT so it is always preempted. + */ + static inline int +-can_preempt(struct task_struct *p, int prio, unsigned long deadline, ++can_preempt(struct task_struct *p, int prio, u64 deadline, + unsigned int policy) + { + /* Better static priority RT task or better policy preemption */ +@@ -1252,7 +1271,8 @@ static inline int needs_other_cpu(struct + static void try_preempt(struct task_struct *p, struct rq *this_rq) + { + struct rq *highest_prio_rq = this_rq; +- unsigned long latest_deadline, cpu; ++ u64 latest_deadline; ++ unsigned long cpu; + int highest_prio; + cpumask_t tmp; + +@@ -1274,7 +1294,7 @@ static void try_preempt(struct task_stru + highest_prio = -1; + + for_each_cpu_mask_nr(cpu, tmp) { +- unsigned long offset_deadline; ++ u64 offset_deadline; + struct rq *rq; + int rq_prio; + +@@ -1975,16 +1995,12 @@ static void pc_user_time(struct rq *rq, + } + + /* Convert nanoseconds to percentage of one tick. */ +-#define NS_TO_PC(NS) (NS * 100 / JIFFIES_TO_NS(1)) ++#define NS_TO_PC(NS) (NS * 100 / JIFFY_NS) + + /* + * This is called on clock ticks and on context switches. + * Bank in p->sched_time the ns elapsed since the last tick or switch. + * CPU scheduler quota accounting is also performed here in microseconds. +- * The value returned from sched_clock() occasionally gives bogus values so +- * some sanity checking is required. Time is supposed to be banked all the +- * time so default to half a tick to make up for when sched_clock reverts +- * to just returning jiffies, and for hardware that can't do tsc. + */ + static void + update_cpu_clock(struct rq *rq, struct task_struct *p, int tick) +@@ -2019,18 +2035,9 @@ update_cpu_clock(struct rq *rq, struct t + + /* time_slice accounting is done in usecs to avoid overflow on 32bit */ + if (rq->rq_policy != SCHED_FIFO && p != idle) { +- long time_diff = rq->clock - rq->rq_last_ran; +- +- /* +- * There should be less than or equal to one jiffy worth, and not +- * negative/overflow. time_diff is only used for internal scheduler +- * time_slice accounting. +- */ +- if (unlikely(time_diff <= 0)) +- time_diff = JIFFIES_TO_NS(1) / 2; +- else if (unlikely(time_diff > JIFFIES_TO_NS(1))) +- time_diff = JIFFIES_TO_NS(1); ++ s64 time_diff = rq->clock - rq->rq_last_ran; + ++ niffy_diff(&time_diff, 1); + rq->rq_time_slice -= NS_TO_US(time_diff); + } + rq->rq_last_ran = rq->timekeep_clock = rq->clock; +@@ -2438,17 +2445,17 @@ EXPORT_SYMBOL(sub_preempt_count); + * proportion works out to the square of the virtual deadline difference, so + * this equation will give nice 19 3% CPU compared to nice 0. + */ +-static inline int prio_deadline_diff(int user_prio) ++static inline u64 prio_deadline_diff(int user_prio) + { + return (prio_ratios[user_prio] * rr_interval * (MS_TO_NS(1) / 128)); + } + +-static inline int task_deadline_diff(struct task_struct *p) ++static inline u64 task_deadline_diff(struct task_struct *p) + { + return prio_deadline_diff(TASK_USER_PRIO(p)); + } + +-static inline int static_deadline_diff(int static_prio) ++static inline u64 static_deadline_diff(int static_prio) + { + return prio_deadline_diff(USER_PRIO(static_prio)); + } +@@ -2504,7 +2511,7 @@ static inline void check_deadline(struct + static inline struct + task_struct *earliest_deadline_task(struct rq *rq, struct task_struct *idle) + { +- unsigned long dl, earliest_deadline = 0; /* Initialise to silence compiler */ ++ u64 dl, earliest_deadline = 0; /* Initialise to silence compiler */ + struct task_struct *p, *edt = idle; + unsigned int cpu = cpu_of(rq); + struct list_head *queue; +@@ -6644,6 +6651,7 @@ void __init sched_init(void) + spin_lock_init(&grq.lock); + grq.nr_running = grq.nr_uninterruptible = grq.nr_switches = 0; + grq.niffies = 0; ++ grq.last_jiffy = jiffies; + spin_lock_init(&grq.iso_lock); + grq.iso_ticks = grq.iso_refractory = 0; + #ifdef CONFIG_SMP +Index: linux-2.6.35.7/include/linux/sched.h +=================================================================== +--- linux-2.6.35.7.orig/include/linux/sched.h 2010-10-04 09:34:58.028244089 +1100 ++++ linux-2.6.35.7/include/linux/sched.h 2010-10-04 09:35:08.833093538 +1100 +@@ -1541,7 +1541,7 @@ static inline void tsk_cpus_current(stru + + static inline void print_scheduler_version(void) + { +- printk(KERN_INFO"BFS CPU scheduler v0.350 by Con Kolivas ported by ToAsTcfh.\n"); ++ printk(KERN_INFO"BFS CPU scheduler v0.357 by Con Kolivas.\n"); + } + + static inline int iso_task(struct task_struct *p) diff --git a/kernel-bfs-2.6.28/debian/patches/mmcnames-fanoush.diff b/kernel-bfs-2.6.28/debian/patches/mmcnames-fanoush.diff index 914aaaf..2124e1f 100644 --- a/kernel-bfs-2.6.28/debian/patches/mmcnames-fanoush.diff +++ b/kernel-bfs-2.6.28/debian/patches/mmcnames-fanoush.diff @@ -11,7 +11,7 @@ __set_bit(devidx, dev_use); --- kernel-power-2.6.28.orig/drivers/mmc/host/omap_hsmmc.c +++ kernel-power-2.6.28/drivers/mmc/host/omap_hsmmc.c -@@ -1759,8 +1759,8 @@ +@@ -1804,8 +1804,8 @@ omap_hsmmc_protect_card(host); mmc_add_host(mmc); diff --git a/kernel-bfs-2.6.28/debian/patches/nokia-20103103+0m5.diff b/kernel-bfs-2.6.28/debian/patches/nokia-20103103+0m5.diff new file mode 100644 index 0000000..a493b7d --- /dev/null +++ b/kernel-bfs-2.6.28/debian/patches/nokia-20103103+0m5.diff @@ -0,0 +1,1439 @@ +--- kernel-power-2.6.28.orig/arch/arm/include/asm/cacheflush.h ++++ kernel-power-2.6.28/arch/arm/include/asm/cacheflush.h +@@ -138,16 +138,16 @@ + * Please note that the implementation of these, and the required + * effects are cache-type (VIVT/VIPT/PIPT) specific. + * +- * flush_cache_kern_all() ++ * flush_kern_all() + * + * Unconditionally clean and invalidate the entire cache. + * +- * flush_cache_user_mm(mm) ++ * flush_user_all() + * + * Clean and invalidate all user space cache entries + * before a change of page tables. + * +- * flush_cache_user_range(start, end, flags) ++ * flush_user_range(start, end, flags) + * + * Clean and invalidate a range of cache entries in the + * specified address space before a change of page tables. +@@ -163,6 +163,20 @@ + * - start - virtual start address + * - end - virtual end address + * ++ * coherent_user_range(start, end) ++ * ++ * Ensure coherency between the Icache and the Dcache in the ++ * region described by start, end. If you have non-snooping ++ * Harvard caches, you need to implement this function. ++ * - start - virtual start address ++ * - end - virtual end address ++ * ++ * flush_kern_dcache_area(kaddr, size) ++ * ++ * Ensure that the data held in page is written back. ++ * - kaddr - page address ++ * - size - region size ++ * + * DMA Cache Coherency + * =================== + * +@@ -375,7 +389,7 @@ + * Harvard caches are synchronised for the user space address range. + * This is used for the ARM private sys_cacheflush system call. + */ +-#define flush_cache_user_range(vma,start,end) \ ++#define flush_cache_user_range(start,end) \ + __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end)) + + /* +--- kernel-power-2.6.28.orig/arch/arm/kernel/traps.c ++++ kernel-power-2.6.28/arch/arm/kernel/traps.c +@@ -418,7 +418,9 @@ + if (end > vma->vm_end) + end = vma->vm_end; + +- flush_cache_user_range(vma, start, end); ++ up_read(&mm->mmap_sem); ++ flush_cache_user_range(start, end); ++ return; + } + up_read(&mm->mmap_sem); + } +--- kernel-power-2.6.28.orig/arch/arm/mach-omap2/smartreflex.c ++++ kernel-power-2.6.28/arch/arm/mach-omap2/smartreflex.c +@@ -890,7 +890,7 @@ + return SR_FAIL; + } + +- if (sr->is_autocomp_active) { ++ if (sr->is_autocomp_active && !sr->is_sr_reset) { + WARN(1, "SR: Must not transmit VCBYPASS command while SR is " + "active"); + return SR_FAIL; +--- kernel-power-2.6.28.orig/arch/arm/mm/fault.c ++++ kernel-power-2.6.28/arch/arm/mm/fault.c +@@ -387,6 +387,9 @@ + if (addr < TASK_SIZE) + return do_page_fault(addr, fsr, regs); + ++ if (user_mode(regs)) ++ goto bad_area; ++ + index = pgd_index(addr); + + /* +@@ -449,7 +452,12 @@ + { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, + { do_bad, SIGKILL, 0, "terminal exception" }, + { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, ++/* Do we need runtime check ? */ ++#if __LINUX_ARM_ARCH__ < 6 + { do_bad, SIGBUS, 0, "external abort on linefetch" }, ++#else ++ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "I-cache maintenance fault" }, ++#endif + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, + { do_bad, SIGBUS, 0, "external abort on linefetch" }, + { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, +--- kernel-power-2.6.28.orig/arch/arm/mm/mmu.c ++++ kernel-power-2.6.28/arch/arm/mm/mmu.c +@@ -953,4 +953,6 @@ + pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); + flush_pmd_entry(pmd); + } ++ ++ local_flush_tlb_all(); + } +--- kernel-power-2.6.28.orig/arch/arm/mm/proc-v6.S ++++ kernel-power-2.6.28/arch/arm/mm/proc-v6.S +@@ -56,8 +56,6 @@ + * to what would be the reset vector. + * + * - loc - location to jump to for soft reset +- * +- * It is assumed that: + */ + .align 5 + ENTRY(cpu_v6_reset) +--- kernel-power-2.6.28.orig/arch/arm/mm/proc-v7.S ++++ kernel-power-2.6.28/arch/arm/mm/proc-v7.S +@@ -28,7 +28,14 @@ + ENDPROC(cpu_v7_proc_init) + + ENTRY(cpu_v7_proc_fin) +- mov pc, lr ++ stmfd sp!, {lr} ++ cpsid if @ disable interrupts ++ bl v7_flush_kern_cache_all ++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register ++ bic r0, r0, #0x1000 @ ...i............ ++ bic r0, r0, #0x0006 @ .............ca. ++ mcr p15, 0, r0, c1, c0, 0 @ disable caches ++ ldmfd sp!, {pc} + ENDPROC(cpu_v7_proc_fin) + + /* +@@ -39,8 +46,6 @@ + * to what would be the reset vector. + * + * - loc - location to jump to for soft reset +- * +- * It is assumed that: + */ + .align 5 + ENTRY(cpu_v7_reset) +--- kernel-power-2.6.28.orig/block/cfq-iosched.c ++++ kernel-power-2.6.28/block/cfq-iosched.c +@@ -84,6 +84,11 @@ + */ + struct cfq_rb_root service_tree; + unsigned int busy_queues; ++ /* ++ * Used to track any pending rt requests so we can pre-empt current ++ * non-RT cfqq in service when this value is non-zero. ++ */ ++ unsigned int busy_rt_queues; + + int rq_in_driver; + int sync_flight; +@@ -155,6 +160,7 @@ + + unsigned long slice_end; + long slice_resid; ++ unsigned int slice_dispatch; + + /* pending metadata requests */ + int meta_pending; +@@ -171,13 +177,12 @@ + enum cfqq_state_flags { + CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ + CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ ++ CFQ_CFQQ_FLAG_must_dispatch, /* must be allowed a dispatch */ + CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ + CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ +- CFQ_CFQQ_FLAG_must_dispatch, /* must dispatch, even if expired */ + CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ + CFQ_CFQQ_FLAG_idle_window, /* slice idling enabled */ + CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ +- CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */ + CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ + CFQ_CFQQ_FLAG_sync, /* synchronous queue */ + }; +@@ -198,13 +203,12 @@ + + CFQ_CFQQ_FNS(on_rr); + CFQ_CFQQ_FNS(wait_request); ++CFQ_CFQQ_FNS(must_dispatch); + CFQ_CFQQ_FNS(must_alloc); + CFQ_CFQQ_FNS(must_alloc_slice); +-CFQ_CFQQ_FNS(must_dispatch); + CFQ_CFQQ_FNS(fifo_expire); + CFQ_CFQQ_FNS(idle_window); + CFQ_CFQQ_FNS(prio_changed); +-CFQ_CFQQ_FNS(queue_new); + CFQ_CFQQ_FNS(slice_new); + CFQ_CFQQ_FNS(sync); + #undef CFQ_CFQQ_FNS +@@ -562,6 +566,8 @@ + BUG_ON(cfq_cfqq_on_rr(cfqq)); + cfq_mark_cfqq_on_rr(cfqq); + cfqd->busy_queues++; ++ if (cfq_class_rt(cfqq)) ++ cfqd->busy_rt_queues++; + + cfq_resort_rr_list(cfqd, cfqq); + } +@@ -581,6 +587,8 @@ + + BUG_ON(!cfqd->busy_queues); + cfqd->busy_queues--; ++ if (cfq_class_rt(cfqq)) ++ cfqd->busy_rt_queues--; + } + + /* +@@ -765,10 +773,15 @@ + if (cfqq) { + cfq_log_cfqq(cfqd, cfqq, "set_active"); + cfqq->slice_end = 0; ++ cfqq->slice_dispatch = 0; ++ ++ cfq_clear_cfqq_wait_request(cfqq); ++ cfq_clear_cfqq_must_dispatch(cfqq); + cfq_clear_cfqq_must_alloc_slice(cfqq); + cfq_clear_cfqq_fifo_expire(cfqq); + cfq_mark_cfqq_slice_new(cfqq); +- cfq_clear_cfqq_queue_new(cfqq); ++ ++ del_timer(&cfqd->idle_slice_timer); + } + + cfqd->active_queue = cfqq; +@@ -786,7 +799,6 @@ + if (cfq_cfqq_wait_request(cfqq)) + del_timer(&cfqd->idle_slice_timer); + +- cfq_clear_cfqq_must_dispatch(cfqq); + cfq_clear_cfqq_wait_request(cfqq); + + /* +@@ -915,7 +927,6 @@ + (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2)) + return; + +- cfq_mark_cfqq_must_dispatch(cfqq); + cfq_mark_cfqq_wait_request(cfqq); + + /* +@@ -1001,10 +1012,24 @@ + /* + * The active queue has run out of time, expire it and select new. + */ +- if (cfq_slice_used(cfqq)) ++ if (cfq_slice_used(cfqq) && !cfq_cfqq_must_dispatch(cfqq)) + goto expire; + + /* ++ * If we have a RT cfqq waiting, then we pre-empt the current non-rt ++ * cfqq. ++ */ ++ if (!cfq_class_rt(cfqq) && cfqd->busy_rt_queues) { ++ /* ++ * We simulate this as cfqq timed out so that it gets to bank ++ * the remaining of its time slice. ++ */ ++ cfq_log_cfqq(cfqd, cfqq, "preempt"); ++ cfq_slice_expired(cfqd, 1); ++ goto new_queue; ++ } ++ ++ /* + * The active queue has requests and isn't expired, allow it to + * dispatch. + */ +@@ -1030,59 +1055,6 @@ + return cfqq; + } + +-/* +- * Dispatch some requests from cfqq, moving them to the request queue +- * dispatch list. +- */ +-static int +-__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, +- int max_dispatch) +-{ +- int dispatched = 0; +- +- BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); +- +- do { +- struct request *rq; +- +- /* +- * follow expired path, else get first next available +- */ +- rq = cfq_check_fifo(cfqq); +- if (rq == NULL) +- rq = cfqq->next_rq; +- +- /* +- * finally, insert request into driver dispatch list +- */ +- cfq_dispatch_insert(cfqd->queue, rq); +- +- dispatched++; +- +- if (!cfqd->active_cic) { +- atomic_inc(&RQ_CIC(rq)->ioc->refcount); +- cfqd->active_cic = RQ_CIC(rq); +- } +- +- if (RB_EMPTY_ROOT(&cfqq->sort_list)) +- break; +- +- } while (dispatched < max_dispatch); +- +- /* +- * expire an async queue immediately if it has used up its slice. idle +- * queue always expire after 1 dispatch round. +- */ +- if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && +- dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) || +- cfq_class_idle(cfqq))) { +- cfqq->slice_end = jiffies + 1; +- cfq_slice_expired(cfqd, 0); +- } +- +- return dispatched; +-} +- + static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) + { + int dispatched = 0; +@@ -1116,11 +1088,45 @@ + return dispatched; + } + ++/* ++ * Dispatch a request from cfqq, moving them to the request queue ++ * dispatch list. ++ */ ++static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) ++{ ++ struct request *rq; ++ ++ BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); ++ ++ /* ++ * follow expired path, else get first next available ++ */ ++ rq = cfq_check_fifo(cfqq); ++ if (!rq) ++ rq = cfqq->next_rq; ++ ++ /* ++ * insert request into driver dispatch list ++ */ ++ cfq_dispatch_insert(cfqd->queue, rq); ++ ++ if (!cfqd->active_cic) { ++ struct cfq_io_context *cic = RQ_CIC(rq); ++ ++ atomic_inc(&cic->ioc->refcount); ++ cfqd->active_cic = cic; ++ } ++} ++ ++/* ++ * Find the cfqq that we need to service and move a request from that to the ++ * dispatch list ++ */ + static int cfq_dispatch_requests(struct request_queue *q, int force) + { + struct cfq_data *cfqd = q->elevator->elevator_data; + struct cfq_queue *cfqq; +- int dispatched; ++ unsigned int max_dispatch; + + if (!cfqd->busy_queues) + return 0; +@@ -1128,33 +1134,63 @@ + if (unlikely(force)) + return cfq_forced_dispatch(cfqd); + +- dispatched = 0; +- while ((cfqq = cfq_select_queue(cfqd)) != NULL) { +- int max_dispatch; ++ cfqq = cfq_select_queue(cfqd); ++ if (!cfqq) ++ return 0; ++ ++ /* ++ * If this is an async queue and we have sync IO in flight, let it wait ++ */ ++ if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq)) ++ return 0; ++ ++ max_dispatch = cfqd->cfq_quantum; ++ if (cfq_class_idle(cfqq)) ++ max_dispatch = 1; + +- max_dispatch = cfqd->cfq_quantum; ++ /* ++ * Does this cfqq already have too much IO in flight? ++ */ ++ if (cfqq->dispatched >= max_dispatch) { ++ /* ++ * idle queue must always only have a single IO in flight ++ */ + if (cfq_class_idle(cfqq)) +- max_dispatch = 1; ++ return 0; + +- if (cfqq->dispatched >= max_dispatch) { +- if (cfqd->busy_queues > 1) +- break; +- if (cfqq->dispatched >= 4 * max_dispatch) +- break; +- } ++ /* ++ * We have other queues, don't allow more IO from this one ++ */ ++ if (cfqd->busy_queues > 1) ++ return 0; + +- if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq)) +- break; ++ /* ++ * we are the only queue, allow up to 4 times of 'quantum' ++ */ ++ if (cfqq->dispatched >= 4 * max_dispatch) ++ return 0; ++ } + +- cfq_clear_cfqq_must_dispatch(cfqq); +- cfq_clear_cfqq_wait_request(cfqq); +- del_timer(&cfqd->idle_slice_timer); ++ /* ++ * Dispatch a request from this cfqq ++ */ ++ cfq_dispatch_request(cfqd, cfqq); ++ cfqq->slice_dispatch++; ++ cfq_clear_cfqq_must_dispatch(cfqq); + +- dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); ++ /* ++ * expire an async queue immediately if it has used up its slice. idle ++ * queue always expire after 1 dispatch round. ++ */ ++ if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && ++ cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) || ++ cfq_class_idle(cfqq))) { ++ cfqq->slice_end = jiffies + 1; ++ cfq_slice_expired(cfqd, 0); + } + +- cfq_log(cfqd, "dispatched=%d", dispatched); +- return dispatched; ++ cfq_log(cfqd, "dispatched a request"); ++ return 1; + } + + /* +@@ -1318,7 +1354,15 @@ + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); +- __cfq_exit_single_io_context(cfqd, cic); ++ ++ /* ++ * Ensure we get a fresh copy of the ->key to prevent ++ * race between exiting task and queue ++ */ ++ smp_read_barrier_depends(); ++ if (cic->key) ++ __cfq_exit_single_io_context(cfqd, cic); ++ + spin_unlock_irqrestore(q->queue_lock, flags); + } + } +@@ -1472,7 +1516,6 @@ + cfqq->cfqd = cfqd; + + cfq_mark_cfqq_prio_changed(cfqq); +- cfq_mark_cfqq_queue_new(cfqq); + + cfq_init_prio_data(cfqq, ioc); + +@@ -1797,6 +1840,12 @@ + if (rq_is_meta(rq) && !cfqq->meta_pending) + return 1; + ++ /* ++ * Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice. ++ */ ++ if (cfq_class_rt(new_cfqq) && !cfq_class_rt(cfqq)) ++ return 1; ++ + if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq)) + return 0; + +@@ -1853,23 +1902,28 @@ + + if (cfqq == cfqd->active_queue) { + /* +- * if we are waiting for a request for this queue, let it rip +- * immediately and flag that we must not expire this queue +- * just now ++ * Remember that we saw a request from this process, but ++ * don't start queuing just yet. Otherwise we risk seeing lots ++ * of tiny requests, because we disrupt the normal plugging ++ * and merging. If the request is already larger than a single ++ * page, let it rip immediately. For that case we assume that ++ * merging is already done. + */ + if (cfq_cfqq_wait_request(cfqq)) { ++ if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE) { ++ del_timer(&cfqd->idle_slice_timer); ++ blk_start_queueing(cfqd->queue); ++ } + cfq_mark_cfqq_must_dispatch(cfqq); +- del_timer(&cfqd->idle_slice_timer); +- blk_start_queueing(cfqd->queue); + } + } else if (cfq_should_preempt(cfqd, cfqq, rq)) { + /* + * not the active queue - expire current slice if it is + * idle and has expired it's mean thinktime or this new queue +- * has some old slice time left and is of higher priority ++ * has some old slice time left and is of higher priority or ++ * this new queue is RT and the current one is BE + */ + cfq_preempt_queue(cfqd, cfqq); +- cfq_mark_cfqq_must_dispatch(cfqq); + blk_start_queueing(cfqd->queue); + } + } +@@ -2129,6 +2183,12 @@ + timed_out = 0; + + /* ++ * We saw a request before the queue expired, let it through ++ */ ++ if (cfq_cfqq_must_dispatch(cfqq)) ++ goto out_kick; ++ ++ /* + * expired + */ + if (cfq_slice_used(cfqq)) +@@ -2144,10 +2204,8 @@ + /* + * not expired and it has a request pending, let it dispatch + */ +- if (!RB_EMPTY_ROOT(&cfqq->sort_list)) { +- cfq_mark_cfqq_must_dispatch(cfqq); ++ if (!RB_EMPTY_ROOT(&cfqq->sort_list)) + goto out_kick; +- } + } + expire: + cfq_slice_expired(cfqd, timed_out); +--- kernel-power-2.6.28.orig/drivers/dsp/bridge/rmgr/drv.c ++++ kernel-power-2.6.28/drivers/dsp/bridge/rmgr/drv.c +@@ -517,11 +517,12 @@ + pDMMRes = pDMMList; + pDMMList = pDMMList->next; + if (pDMMRes->dmmAllocated) { +- status = PROC_UnMap(pDMMRes->hProcessor, +- (void *)pDMMRes->ulDSPResAddr, pCtxt); +- status = PROC_UnReserveMemory(pDMMRes->hProcessor, +- (void *)pDMMRes->ulDSPResAddr); +- pDMMRes->dmmAllocated = 0; ++ /* PROC_UnMap frees pDMMRes */ ++ void *processor = pDMMRes->hProcessor; ++ void *map_addr = (void*)pDMMRes->ulDSPAddr; ++ void *rsv_addr = (void*)pDMMRes->ulDSPResAddr; ++ status = PROC_UnMap(processor, map_addr, pCtxt); ++ status = PROC_UnReserveMemory(processor, rsv_addr); + } + } + return status; +--- kernel-power-2.6.28.orig/drivers/dsp/bridge/rmgr/proc.c ++++ kernel-power-2.6.28/drivers/dsp/bridge/rmgr/proc.c +@@ -750,6 +750,7 @@ + break; + + start = vma->vm_end; ++ len -= size; + } + + if (!vma) +--- kernel-power-2.6.28.orig/drivers/i2c/chips/lis302dl.c ++++ kernel-power-2.6.28/drivers/i2c/chips/lis302dl.c +@@ -44,6 +44,7 @@ + # define LIS302_CTRL1_Y (1 << 1) + # define LIS302_CTRL1_X (1 << 0) + #define LIS302_CTRL_2 0x21 ++# define LIS302_CTRL2_BOOT (1 << 6) + #define LIS302_CTRL_3 0x22 + # define LIS302_CTRL3_GND 0x00 + # define LIS302_CTRL3_FF_WU_1 0x01 +@@ -161,8 +162,13 @@ + if (ret < 0) + goto out; + +- /* REG 2 */ +- /* Control High Pass filter selection. not used */ ++ /* REG 2 ++ * Boot is used to refresh internal registers ++ * Control High Pass filter selection. not used ++ */ ++ ret = lis302dl_write(c, LIS302_CTRL_2, LIS302_CTRL2_BOOT); ++ if (ret < 0) ++ goto out; + + /* REG 3 + * Interrupt CTRL register. One interrupt pin is used for +--- kernel-power-2.6.28.orig/drivers/leds/leds-lp5523.c ++++ kernel-power-2.6.28/drivers/leds/leds-lp5523.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #define LP5523_DRIVER_NAME "lp5523" + #define LP5523_REG_ENABLE 0x00 +@@ -120,6 +121,8 @@ + u8 led_nr; + u8 led_current; + struct led_classdev cdev; ++ struct work_struct brightness_work; ++ u8 brightness; + }; + + struct lp5523_chip { +@@ -161,6 +164,8 @@ + static void lp5523_work(struct work_struct *work); + static irqreturn_t lp5523_irq(int irq, void *_chip); + ++static void lp5523_led_brightness_work(struct work_struct *work); ++ + + static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) + { +@@ -476,6 +481,16 @@ + enum led_brightness brightness) + { + struct lp5523_led *led = cdev_to_led(cdev); ++ led->brightness = (u8)brightness; ++ ++ schedule_work(&led->brightness_work); ++} ++ ++static void lp5523_led_brightness_work(struct work_struct *work) ++{ ++ struct lp5523_led *led = container_of(work, ++ struct lp5523_led, ++ brightness_work); + struct lp5523_chip *chip = led_to_lp5523(led); + struct i2c_client *client = chip->client; + +@@ -483,7 +498,7 @@ + + lp5523_write(client, + LP5523_REG_LED_PWM_BASE + led->led_nr, +- (u8)brightness); ++ led->brightness); + + mutex_unlock(&chip->lock); + } +@@ -907,6 +922,8 @@ + dev_err(&client->dev, "error initializing leds\n"); + goto fail2; + } ++ INIT_WORK(&(chip->leds[i].brightness_work), ++ lp5523_led_brightness_work); + } + + ret = lp5523_register_sysfs(client); +@@ -916,8 +933,10 @@ + } + return ret; + fail2: +- for (i = 0; i < pdata->num_leds; i++) ++ for (i = 0; i < pdata->num_leds; i++) { + led_classdev_unregister(&chip->leds[i].cdev); ++ cancel_work_sync(&chip->leds[i].brightness_work); ++ } + + fail1: + kfree(chip); +@@ -931,8 +950,10 @@ + + lp5523_unregister_sysfs(client); + +- for (i = 0; i < chip->num_leds; i++) ++ for (i = 0; i < chip->num_leds; i++) { + led_classdev_unregister(&chip->leds[i].cdev); ++ cancel_work_sync(&chip->leds[i].brightness_work); ++ } + + kfree(chip); + +--- kernel-power-2.6.28.orig/drivers/media/radio/radio-si4713.c ++++ kernel-power-2.6.28/drivers/media/radio/radio-si4713.c +@@ -54,6 +54,25 @@ + /* module parameters */ + static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */ + ++/* properties lock for write operations */ ++static int config_locked; ++ ++/* saved power levels */ ++static unsigned int max_pl; ++static unsigned int min_pl; ++ ++/* structure for pid registration */ ++struct pid_list { ++ pid_t pid; ++ struct list_head plist; ++}; ++ ++#define APP_MAX_NUM 2 ++ ++static int pid_count; ++static LIST_HEAD(pid_list_head); ++static struct si4713_device *si4713_dev; ++ + /* + * Sysfs properties + * Read and write functions +@@ -167,6 +186,37 @@ + si4713_##prop##_write); + + /* ++ * Config lock property ++ */ ++static ssize_t si4713_lock_write(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t count) ++{ ++ int l; ++ ++ if (config_locked) ++ return -EPERM; ++ ++ sscanf(buf, "%d", &l); ++ ++ if (l != 0) ++ config_locked = 1; ++ ++ return count; ++} ++ ++static ssize_t si4713_lock_read(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf, "%d\n", config_locked); ++} ++ ++static DEVICE_ATTR(lock, S_IRUGO | S_IWUSR, si4713_lock_read, ++ si4713_lock_write); ++ ++/* + * Power level property + */ + /* power_level (rw) 88 - 115 or 0 */ +@@ -179,6 +229,9 @@ + unsigned int p; + int rval, pl; + ++ if (config_locked) ++ return -EPERM; ++ + if (!sdev) { + rval = -ENODEV; + goto exit; +@@ -320,6 +373,7 @@ + value > MAX_TONE_OFF_TIME) + + static struct attribute *attrs[] = { ++ &dev_attr_lock.attr, + &dev_attr_power_level.attr, + &dev_attr_antenna_capacitor.attr, + &dev_attr_rds_pi.attr, +@@ -366,13 +420,118 @@ + return IRQ_HANDLED; + } + ++static int register_pid(pid_t pid) ++{ ++ struct pid_list *pitem; ++ ++ list_for_each_entry(pitem, &pid_list_head, plist) { ++ if (pitem->pid == pid) ++ return -EINVAL; ++ } ++ ++ pitem = kmalloc(sizeof(struct pid_list), GFP_KERNEL); ++ ++ if (!pitem) ++ return -ENOMEM; ++ ++ pitem->pid = pid; ++ ++ list_add(&(pitem->plist), &pid_list_head); ++ pid_count++; ++ ++ return 0; ++} ++ ++static int unregister_pid(pid_t pid) ++{ ++ struct pid_list *pitem, *n; ++ ++ list_for_each_entry_safe(pitem, n, &pid_list_head, plist) { ++ if (pitem->pid == pid) { ++ list_del(&(pitem->plist)); ++ pid_count--; ++ ++ kfree(pitem); ++ ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++static int si4713_priv_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned int pow; ++ int pl, rval; ++ ++ if (cmd != LOCK_LOW_POWER && cmd != RELEASE_LOW_POWER) ++ return video_ioctl2(inode, file, cmd, arg); ++ ++ pl = si4713_get_power_level(si4713_dev); ++ ++ if (pl < 0) { ++ rval = pl; ++ goto exit; ++ } ++ ++ if (copy_from_user(&pow, (void __user *)arg, sizeof(pow))) { ++ rval = -EFAULT; ++ goto exit; ++ } ++ ++ if (cmd == LOCK_LOW_POWER) { ++ ++ if (pid_count == APP_MAX_NUM) { ++ rval = -EPERM; ++ goto exit; ++ } ++ ++ if (pid_count == 0) { ++ if (pow > pl) { ++ rval = -EINVAL; ++ goto exit; ++ } else { ++ /* Set max possible power level */ ++ max_pl = pl; ++ min_pl = pow; ++ } ++ } ++ ++ rval = register_pid(current->pid); ++ ++ if (rval) ++ goto exit; ++ ++ /* Lower min power level if asked */ ++ if (pow < min_pl) ++ min_pl = pow; ++ else ++ pow = min_pl; ++ ++ } else { /* RELEASE_LOW_POWER */ ++ rval = unregister_pid(current->pid); ++ ++ if (rval) ++ goto exit; ++ ++ if (pid_count == 0) { ++ if (pow > max_pl) ++ pow = max_pl; ++ } ++ } ++ rval = si4713_set_power_level(si4713_dev, pow); ++exit: ++ return rval; ++} ++ + /* + * si4713_fops - file operations interface + */ + static const struct file_operations si4713_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, +- .ioctl = video_ioctl2, ++ .ioctl = si4713_priv_ioctl, + .compat_ioctl = v4l_compat_ioctl32, + }; + +@@ -747,6 +906,9 @@ + goto free_sysfs; + } + ++ /* save to global pointer for it to be accesible from ioctl() call */ ++ si4713_dev = sdev; ++ + return 0; + + free_sysfs: +--- kernel-power-2.6.28.orig/drivers/media/radio/radio-si4713.h ++++ kernel-power-2.6.28/drivers/media/radio/radio-si4713.h +@@ -21,6 +21,9 @@ + #define SI4713_I2C_ADDR_BUSEN_HIGH 0x63 + #define SI4713_I2C_ADDR_BUSEN_LOW 0x11 + ++#define LOCK_LOW_POWER _IOW('v', BASE_VIDIOC_PRIVATE + 0, unsigned int) ++#define RELEASE_LOW_POWER _IOW('v', BASE_VIDIOC_PRIVATE + 1, unsigned int) ++ + /* + * Platform dependent definition + */ +--- kernel-power-2.6.28.orig/drivers/media/video/omap34xxcam.c ++++ kernel-power-2.6.28/drivers/media/video/omap34xxcam.c +@@ -1833,6 +1833,7 @@ + struct omap34xxcam_videodev *vdev = fh->vdev; + struct device *isp = vdev->cam->isp; + int i; ++ int streamoff = 0; + + if (omap34xxcam_daemon_release(vdev, file)) + goto daemon_out; +@@ -1844,6 +1845,7 @@ + omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY, + OMAP34XXCAM_SLAVE_POWER_ALL); + vdev->streaming = NULL; ++ streamoff = 1; + } + + if (atomic_dec_return(&vdev->users) == 0) { +@@ -1853,6 +1855,10 @@ + } + mutex_unlock(&vdev->mutex); + ++ if (streamoff) ++ omap34xxcam_daemon_req_hw_reconfig( ++ vdev, OMAP34XXCAM_DAEMON_HW_RECONFIG_STREAMOFF); ++ + daemon_out: + file->private_data = NULL; + +--- kernel-power-2.6.28.orig/drivers/mmc/host/omap_hsmmc.c ++++ kernel-power-2.6.28/drivers/mmc/host/omap_hsmmc.c +@@ -115,6 +115,7 @@ + /* Timeouts for entering power saving states on inactivity, msec */ + #define OMAP_MMC_DISABLED_TIMEOUT 100 + #define OMAP_MMC_SLEEP_TIMEOUT 1000 ++#define OMAP_MMC_OFF_NOSLP_TIMEOUT 3000 + #define OMAP_MMC_OFF_TIMEOUT 8000 + + /* +@@ -1249,21 +1250,21 @@ + + /* + * Dynamic power saving handling, FSM: +- * ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF +- * ^___________| | | +- * |______________________|______________________| ++ * ENABLED -> DISABLED -> EXTDISABLED / CARDSLEEP / REGSLEEP -> OFF ++ * ^___________| | | ++ * |____________________________________|______________________| + * +- * ENABLED: mmc host is fully functional +- * DISABLED: fclk is off +- * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep +- * REGSLEEP: fclk is off, voltage regulator is asleep +- * OFF: fclk is off, voltage regulator is off ++ * ENABLED: mmc host is fully functional ++ * (EXT)DISABLED: fclk is off ++ * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep ++ * REGSLEEP: fclk is off, voltage regulator is asleep ++ * OFF: fclk is off, voltage regulator is off + * + * Transition handlers return the timeout for the next state transition + * or negative error. + */ + +-enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF}; ++enum {ENABLED = 0, DISABLED, EXTDISABLED, CARDSLEEP, REGSLEEP, OFF}; + + /* Handler for [ENABLED -> DISABLED] transition */ + static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host) +@@ -1300,7 +1301,21 @@ + return 1; + } + +-/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */ ++/* Big SD cards (16GiB) are prohibited from ++ switching voltage regulator to asleep ++ because of high current consumption */ ++static int omap_hsmmc_support_sleep(struct mmc_host *mmc) ++{ ++ if (!(mmc->caps & MMC_CAP_NONREMOVABLE) && ++ ((u64)mmc->card->csd.capacity << mmc->card->csd.read_blkbits) > ++ 14ULL * 1024 * 1024 * 1024) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* Handler for [DISABLED -> EXTDISABLED / REGSLEEP / CARDSLEEP] transition */ + static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) + { + int err, new_state, sleep; +@@ -1319,12 +1334,12 @@ + } + new_state = CARDSLEEP; + } else { +- new_state = REGSLEEP; ++ new_state = omap_hsmmc_support_sleep(host->mmc) ? REGSLEEP : EXTDISABLED; + } + + sleep = omap_hsmmc_full_sleep(host->mmc->card) && + (new_state == CARDSLEEP); +- if (mmc_slot(host).set_sleep) ++ if (mmc_slot(host).set_sleep && new_state != EXTDISABLED) + mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0, + sleep); + /* FIXME: turn off bus power and perhaps interrupts too */ +@@ -1334,18 +1349,20 @@ + mmc_release_host(host->mmc); + + dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n", +- host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); ++ host->dpm_state == CARDSLEEP ? "CARDSLEEP" : ++ host->dpm_state == REGSLEEP ? "REGSLEEP" : "EXTDISABLED"); + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + mmc_slot(host).card_detect || + (mmc_slot(host).get_cover_state && + mmc_slot(host).get_cover_state(host->dev, host->slot_id))) +- return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT); ++ return msecs_to_jiffies(new_state == EXTDISABLED ? ++ OMAP_MMC_OFF_NOSLP_TIMEOUT : OMAP_MMC_OFF_TIMEOUT); + + return 0; + } + +-/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */ ++/* Handler for [EXTDISABLED / REGSLEEP / CARDSLEEP -> OFF] transition */ + static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) + { + if (!mmc_try_claim_host(host->mmc)) +@@ -1364,7 +1381,8 @@ + host->power_mode = MMC_POWER_OFF; + + dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n", +- host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); ++ host->dpm_state == CARDSLEEP ? "CARDSLEEP" : ++ host->dpm_state == REGSLEEP ? "REGSLEEP" : "EXTDISABLED"); + + host->dpm_state = OFF; + +@@ -1405,14 +1423,15 @@ + omap_hsmmc_context_restore(host); + asleep = omap_hsmmc_full_sleep(host->mmc->card) && + (host->dpm_state == CARDSLEEP); +- if (mmc_slot(host).set_sleep) ++ if (mmc_slot(host).set_sleep && host->dpm_state != EXTDISABLED) + mmc_slot(host).set_sleep(host->dev, host->slot_id, 0, + host->vdd, asleep); + if (mmc_card_can_sleep(host->mmc)) + mmc_card_awake(host->mmc); + + dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n", +- host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); ++ host->dpm_state == CARDSLEEP ? "CARDSLEEP" : ++ host->dpm_state == REGSLEEP ? "REGSLEEP" : "EXTDISABLED"); + + if (host->pdata->set_pm_constraints) + host->pdata->set_pm_constraints(host->dev, 1); +@@ -1454,6 +1473,7 @@ + switch (host->dpm_state) { + case DISABLED: + return omap_hsmmc_disabled_to_enabled(host); ++ case EXTDISABLED: + case CARDSLEEP: + case REGSLEEP: + return omap_hsmmc_sleep_to_enabled(host); +@@ -1484,6 +1504,7 @@ + } + case DISABLED: + return omap_hsmmc_disabled_to_sleep(host); ++ case EXTDISABLED: + case CARDSLEEP: + case REGSLEEP: + return omap_hsmmc_sleep_to_off(host); +--- kernel-power-2.6.28.orig/drivers/net/wireless/wl12xx/wl1251_acx.c ++++ kernel-power-2.6.28/drivers/net/wireless/wl12xx/wl1251_acx.c +@@ -910,7 +910,7 @@ + } + + *mactime = tsf_info->current_tsf_lsb | +- (tsf_info->current_tsf_msb << 31); ++ ((unsigned long long) tsf_info->current_tsf_msb << 32); + + out: + kfree(tsf_info); +--- kernel-power-2.6.28.orig/drivers/net/wireless/wl12xx/wl1251_cmd.c ++++ kernel-power-2.6.28/drivers/net/wireless/wl12xx/wl1251_cmd.c +@@ -242,7 +242,7 @@ + if (ret < 0) { + wl1251_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); +- return ret; ++ goto out; + } + + wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", +--- kernel-power-2.6.28.orig/drivers/usb/musb/musb_core.c ++++ kernel-power-2.6.28/drivers/usb/musb/musb_core.c +@@ -297,28 +297,23 @@ + break; + } + +- if (vdat) { +- /* REVISIT: This code works only with dedicated chargers! +- * When support for HOST/HUB chargers is added, don't +- * forget this. +- */ ++ /* enable interrupts */ ++ musb_writeb(musb->mregs, MUSB_INTRUSBE, ctx.intrusbe); ++ ++ /* Make sure the communication starts normally */ ++ r = musb_readb(musb->mregs, MUSB_POWER); ++ musb_writeb(musb->mregs, MUSB_POWER, ++ r | MUSB_POWER_RESUME); ++ msleep(10); ++ musb_writeb(musb->mregs, MUSB_POWER, ++ r & ~MUSB_POWER_RESUME); ++ if (vdat && musb->xceiv->state != OTG_STATE_B_IDLE) { + musb_stop(musb); + /* Regulators off */ + otg_set_suspend(musb->xceiv, 1); +- musb->is_charger = 1; +- } else { +- /* enable interrupts */ +- musb_writeb(musb->mregs, MUSB_INTRUSBE, ctx.intrusbe); +- +- /* Make sure the communication starts normally */ +- r = musb_readb(musb->mregs, MUSB_POWER); +- musb_writeb(musb->mregs, MUSB_POWER, +- r | MUSB_POWER_RESUME); +- msleep(10); +- musb_writeb(musb->mregs, MUSB_POWER, +- r & ~MUSB_POWER_RESUME); + } + ++ musb->is_charger = vdat; + check_charger = 0; + + return vdat; +--- kernel-power-2.6.28.orig/include/linux/sched.h ++++ kernel-power-2.6.28/include/linux/sched.h +@@ -1665,11 +1665,11 @@ + static inline void wake_up_idle_cpu(int cpu) { } + #endif + ++extern unsigned int sysctl_sched_child_runs_first; + #ifdef CONFIG_SCHED_DEBUG + extern unsigned int sysctl_sched_latency; + extern unsigned int sysctl_sched_min_granularity; + extern unsigned int sysctl_sched_wakeup_granularity; +-extern unsigned int sysctl_sched_child_runs_first; + extern unsigned int sysctl_sched_features; + extern unsigned int sysctl_sched_migration_cost; + extern unsigned int sysctl_sched_nr_migrate; +--- kernel-power-2.6.28.orig/include/linux/swap.h ++++ kernel-power-2.6.28/include/linux/swap.h +@@ -130,6 +130,17 @@ + #define SWAP_MAP_MAX 0x7fff + #define SWAP_MAP_BAD 0x8000 + ++#define SWAP_GAP_TREE_SIZE 10 ++#define SWAP_GAP_RESCAN_TIMEO_MSEC 2000 ++#define swap_gap_len(gap) ((gap)->end - (gap)->next) ++#define swap_gap_rb_entry(node) rb_entry(node, struct swap_gap_node, rb_node) ++/* Struct to store gaps info */ ++struct swap_gap_node { ++ struct rb_node rb_node; ++ unsigned int next; ++ unsigned int end; ++}; ++ + /* + * The in-memory structure used to track swap areas. + */ +@@ -157,6 +168,9 @@ + unsigned int gap_next; + unsigned int gap_end; + unsigned int gaps_exist; ++ struct rb_root gaps_tree; ++ struct swap_gap_node *gap_pool_arr; ++ unsigned long gap_last_scan; + unsigned int lowest_bit; + unsigned int highest_bit; + unsigned int cluster_next; +--- kernel-power-2.6.28.orig/include/net/bluetooth/sco.h ++++ kernel-power-2.6.28/include/net/bluetooth/sco.h +@@ -29,7 +29,7 @@ + #define SCO_DEFAULT_MTU 500 + #define SCO_DEFAULT_FLUSH_TO 0xFFFF + +-#define SCO_CONN_TIMEOUT (HZ * 40) ++#define SCO_CONN_TIMEOUT (HZ * 25) + #define SCO_DISCONN_TIMEOUT (HZ * 2) + #define SCO_CONN_IDLE_TIMEOUT (HZ * 60) + +--- kernel-power-2.6.28.orig/kernel/sched_fair.c ++++ kernel-power-2.6.28/kernel/sched_fair.c +@@ -48,10 +48,10 @@ + static unsigned int sched_nr_latency = 5; + + /* +- * After fork, child runs first. (default) If set to 0 then ++ * After fork, child runs first. If set to 0 then + * parent will (try to) run first. + */ +-const_debug unsigned int sysctl_sched_child_runs_first = 1; ++unsigned int sysctl_sched_child_runs_first __read_mostly; + + /* + * sys_sched_yield() compat mode +--- kernel-power-2.6.28.orig/kernel/sysctl.c ++++ kernel-power-2.6.28/kernel/sysctl.c +@@ -235,6 +235,14 @@ + #endif + + static struct ctl_table kern_table[] = { ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "sched_child_runs_first", ++ .data = &sysctl_sched_child_runs_first, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, + #ifdef CONFIG_SCHED_DEBUG + { + .ctl_name = CTL_UNNUMBERED, +@@ -289,14 +297,6 @@ + }, + { + .ctl_name = CTL_UNNUMBERED, +- .procname = "sched_child_runs_first", +- .data = &sysctl_sched_child_runs_first, +- .maxlen = sizeof(unsigned int), +- .mode = 0644, +- .proc_handler = &proc_dointvec, +- }, +- { +- .ctl_name = CTL_UNNUMBERED, + .procname = "sched_features", + .data = &sysctl_sched_features, + .maxlen = sizeof(unsigned int), +--- kernel-power-2.6.28.orig/mm/swapfile.c ++++ kernel-power-2.6.28/mm/swapfile.c +@@ -996,11 +996,55 @@ + spin_unlock(&mmlist_lock); + } + ++void gaps_rbtree_insert(struct swap_info_struct *sis, ++ struct swap_gap_node *node) ++{ ++ struct rb_node **p = &sis->gaps_tree.rb_node; ++ struct rb_node *parent = NULL; ++ struct swap_gap_node *tmp; ++ ++ while (*p) { ++ parent = *p; ++ tmp = rb_entry(parent, struct swap_gap_node, rb_node); ++ if (swap_gap_len(node) < swap_gap_len(tmp)) ++ p = &(*p)->rb_left; ++ else ++ p = &(*p)->rb_right; ++ } ++ rb_link_node(&node->rb_node, parent, p); ++ rb_insert_color(&node->rb_node, &sis->gaps_tree); ++} ++ ++void gaps_rbtree_add(struct swap_info_struct *sis, ++ unsigned int next, unsigned int end, ++ struct swap_gap_node **gap_min, int *pos) ++{ ++ struct swap_gap_node *gap_node; ++ if (*pos < SWAP_GAP_TREE_SIZE) { ++ gap_node = &sis->gap_pool_arr[*pos]; ++ *pos += 1; ++ } else if (swap_gap_len(*gap_min) > end - next) { ++ return; ++ } else { ++ gap_node = *gap_min; ++ rb_erase(&gap_node->rb_node, &sis->gaps_tree); ++ *gap_min = swap_gap_rb_entry(rb_first(&sis->gaps_tree)); ++ } ++ gap_node->next = next; ++ gap_node->end = end; ++ if (gap_min && (*gap_min == NULL || ++ swap_gap_len(*gap_min) > swap_gap_len(gap_node))) ++ *gap_min = gap_node; ++ gaps_rbtree_insert(sis, gap_node); ++} ++ + /* Find the largest sequence of free pages */ + int find_gap(struct swap_info_struct *sis) + { + unsigned i, uninitialized_var(start), uninitialized_var(gap_next); +- unsigned uninitialized_var(gap_end), gap_size = 0; ++ unsigned uninitialized_var(gap_end); ++ struct swap_gap_node *gap_max, *gap_min = NULL; ++ int pos = 0; + int in_gap = 0; + + spin_unlock(&sis->remap_lock); +@@ -1017,6 +1061,11 @@ + mutex_unlock(&sis->remap_mutex); + return -1; + } ++ if (time_after(jiffies, sis->gap_last_scan + ++ msecs_to_jiffies(SWAP_GAP_RESCAN_TIMEO_MSEC))) ++ sis->gaps_tree = RB_ROOT; ++ if (!RB_EMPTY_ROOT(&sis->gaps_tree)) ++ goto out; + spin_unlock(&sis->remap_lock); + + /* +@@ -1028,11 +1077,7 @@ + if (in_gap) { + if (!(sis->swap_remap[i] & 0x80000000)) + continue; +- if (i - start > gap_size) { +- gap_next = start; +- gap_end = i - 1; +- gap_size = i - start; +- } ++ gaps_rbtree_add(sis, start, i - 1, &gap_min, &pos); + in_gap = 0; + } else { + if (sis->swap_remap[i] & 0x80000000) +@@ -1043,13 +1088,14 @@ + cond_resched(); + } + spin_lock(&sis->remap_lock); +- if (in_gap && i - start > gap_size) { +- sis->gap_next = start; +- sis->gap_end = i - 1; +- } else { +- sis->gap_next = gap_next; +- sis->gap_end = gap_end; +- } ++ if (in_gap) ++ gaps_rbtree_add(sis, start, i - 1, &gap_min, &pos); ++ sis->gap_last_scan = jiffies; ++out: ++ gap_max = swap_gap_rb_entry(rb_last(&sis->gaps_tree)); ++ rb_erase(&gap_max->rb_node, &sis->gaps_tree); ++ sis->gap_next = gap_max->next; ++ sis->gap_end = gap_max->end; + mutex_unlock(&sis->remap_mutex); + return 0; + } +@@ -1471,6 +1517,7 @@ + p->flags = 0; + spin_unlock(&swap_lock); + mutex_unlock(&swapon_mutex); ++ kfree(p->gap_pool_arr); + vfree(p->swap_remap); + vfree(swap_map); + inode = mapping->host; +@@ -1825,6 +1872,14 @@ + goto bad_swap; + } + ++ p->gap_pool_arr = kmalloc(sizeof(struct swap_gap_node)* ++ SWAP_GAP_TREE_SIZE, GFP_KERNEL); ++ if (!p->gap_pool_arr) { ++ error = -ENOMEM; ++ goto bad_swap; ++ } ++ p->gaps_tree = RB_ROOT; ++ + mutex_lock(&swapon_mutex); + spin_lock(&swap_lock); + if (swap_flags & SWAP_FLAG_PREFER) +--- kernel-power-2.6.28.orig/net/bluetooth/hci_conn.c ++++ kernel-power-2.6.28/net/bluetooth/hci_conn.c +@@ -375,6 +375,9 @@ + + if (acl->state == BT_CONNECTED && + (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { ++ acl->power_save = 1; ++ hci_conn_enter_active_mode(acl); ++ + if (lmp_esco_capable(hdev)) + hci_setup_sync(sco, acl->handle); + else +--- kernel-power-2.6.28.orig/net/bluetooth/hci_event.c ++++ kernel-power-2.6.28/net/bluetooth/hci_event.c +@@ -1056,6 +1056,8 @@ + if (conn) { + if (!ev->status) + conn->link_mode |= HCI_LM_AUTH; ++ else ++ conn->sec_level = BT_SECURITY_LOW; + + clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); + +@@ -1709,6 +1711,7 @@ + break; + + case 0x1c: /* SCO interval rejected */ ++ case 0x1a: /* Unsupported Remote Feature */ + case 0x1f: /* Unspecified error */ + if (conn->out && conn->attempt < 2) { + conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | diff --git a/kernel-bfs-2.6.28/debian/patches/series b/kernel-bfs-2.6.28/debian/patches/series index 2a5c020..9376b4f 100644 --- a/kernel-bfs-2.6.28/debian/patches/series +++ b/kernel-bfs-2.6.28/debian/patches/series @@ -1,6 +1,8 @@ +strip_cfs_nokia_pr13.diff nokia-20094803.3+0m5.diff nokia-20100903+0m5.diff nokia-20101501+0m5.diff +nokia-20103103+0m5.diff maemo-build.diff unionfs-2.5.3.diff dm-loop.diff @@ -12,9 +14,9 @@ ppp_async_matan.diff 2.6.28.10.diff block2mtd-yoush.diff gentoo-fsfixes.diff -kexec.diff +#kexec.diff bq_matan.diff -leds-lp5523.diff +#leds-lp5523.diff trig-keyb.diff twl-scrollock.diff squashfs.diff @@ -35,7 +37,9 @@ bfs-316-to-318.patch bfs-318-to-330.patch sched_reset_on_fork.diff bfs-330-to-350.patch +bfs-350-to-357.patch voltage_scaling_1.diff voltage_scaling_0.diff armthumb.diff +wl12xx_rohar.diff #issue_12309_0.diff diff --git a/kernel-bfs-2.6.28/debian/patches/strip_cfs_nokia_pr13.diff b/kernel-bfs-2.6.28/debian/patches/strip_cfs_nokia_pr13.diff new file mode 100644 index 0000000..983805a --- /dev/null +++ b/kernel-bfs-2.6.28/debian/patches/strip_cfs_nokia_pr13.diff @@ -0,0 +1,78 @@ +--- kernel-2.6.28.orig/debian/patches/nokia-20103103+0m5.diff 2010-11-09 22:25:45.000000000 +0100 ++++ kernel-2.6.28/debian/patches/nokia-20103103+0m5.diff 2010-11-09 23:26:15.586667441 +0100 +@@ -1174,21 +1174,6 @@ + check_charger = 0; + + return vdat; +---- kernel-power-2.6.28.orig/include/linux/sched.h +-+++ kernel-power-2.6.28/include/linux/sched.h +-@@ -1665,11 +1665,11 @@ +- static inline void wake_up_idle_cpu(int cpu) { } +- #endif +- +-+extern unsigned int sysctl_sched_child_runs_first; +- #ifdef CONFIG_SCHED_DEBUG +- extern unsigned int sysctl_sched_latency; +- extern unsigned int sysctl_sched_min_granularity; +- extern unsigned int sysctl_sched_wakeup_granularity; +--extern unsigned int sysctl_sched_child_runs_first; +- extern unsigned int sysctl_sched_features; +- extern unsigned int sysctl_sched_migration_cost; +- extern unsigned int sysctl_sched_nr_migrate; + --- kernel-power-2.6.28.orig/include/linux/swap.h + +++ kernel-power-2.6.28/include/linux/swap.h + @@ -130,6 +130,17 @@ +@@ -1230,53 +1215,6 @@ + #define SCO_DISCONN_TIMEOUT (HZ * 2) + #define SCO_CONN_IDLE_TIMEOUT (HZ * 60) + +---- kernel-power-2.6.28.orig/kernel/sched_fair.c +-+++ kernel-power-2.6.28/kernel/sched_fair.c +-@@ -48,10 +48,10 @@ +- static unsigned int sched_nr_latency = 5; +- +- /* +-- * After fork, child runs first. (default) If set to 0 then +-+ * After fork, child runs first. If set to 0 then +- * parent will (try to) run first. +- */ +--const_debug unsigned int sysctl_sched_child_runs_first = 1; +-+unsigned int sysctl_sched_child_runs_first __read_mostly; +- +- /* +- * sys_sched_yield() compat mode +---- kernel-power-2.6.28.orig/kernel/sysctl.c +-+++ kernel-power-2.6.28/kernel/sysctl.c +-@@ -235,6 +235,14 @@ +- #endif +- +- static struct ctl_table kern_table[] = { +-+ { +-+ .ctl_name = CTL_UNNUMBERED, +-+ .procname = "sched_child_runs_first", +-+ .data = &sysctl_sched_child_runs_first, +-+ .maxlen = sizeof(unsigned int), +-+ .mode = 0644, +-+ .proc_handler = &proc_dointvec, +-+ }, +- #ifdef CONFIG_SCHED_DEBUG +- { +- .ctl_name = CTL_UNNUMBERED, +-@@ -289,14 +297,6 @@ +- }, +- { +- .ctl_name = CTL_UNNUMBERED, +-- .procname = "sched_child_runs_first", +-- .data = &sysctl_sched_child_runs_first, +-- .maxlen = sizeof(unsigned int), +-- .mode = 0644, +-- .proc_handler = &proc_dointvec, +-- }, +-- { +-- .ctl_name = CTL_UNNUMBERED, +- .procname = "sched_features", +- .data = &sysctl_sched_features, +- .maxlen = sizeof(unsigned int), + --- kernel-power-2.6.28.orig/mm/swapfile.c + +++ kernel-power-2.6.28/mm/swapfile.c + @@ -996,11 +996,55 @@ diff --git a/kernel-bfs-2.6.28/debian/patches/wl12xx_rohar.diff b/kernel-bfs-2.6.28/debian/patches/wl12xx_rohar.diff new file mode 100644 index 0000000..7ae7775 --- /dev/null +++ b/kernel-bfs-2.6.28/debian/patches/wl12xx_rohar.diff @@ -0,0 +1,14 @@ +--- kernel-power-2.6.28.orig/drivers/net/wireless/wl12xx/wl1251_main.c ++++ kernel-power-2.6.28/drivers/net/wireless/wl12xx/wl1251_main.c +@@ -1923,6 +1923,11 @@ + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_BEACON_FILTER; + ++ wl->hw->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_ADHOC) | ++ BIT(NL80211_IFTYPE_MONITOR); ++ + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; + + wl->hw->queues = 4; diff --git a/kernel-bfs-2.6.28/debian/rules b/kernel-bfs-2.6.28/debian/rules index 42dd895..f8666a8 100644 --- a/kernel-bfs-2.6.28/debian/rules +++ b/kernel-bfs-2.6.28/debian/rules @@ -4,7 +4,7 @@ WEEK := $(shell date +%Y%W) RELEASE := $(shell dpkg-parsechangelog | awk '/^Version: / { print $$2 }') REVISION := $(shell echo "$(RELEASE)" | sed 's/\(.*\)-maemo\(.*\)/.10bfs\2/') -EXTRAVERSION := EXTRAVERSION=$(REVISION) +EXTRAVERSION := EXTRAVERSION=-bfs2 PACKAGE := kernel FLASHER_PACKAGE := kernel-bfs-flasher @@ -163,6 +163,7 @@ install-headers: #kbuild fixes cd $(CURDIR)/debian/$(HEADERS_PACKAGE)/usr/src/$(KBUILD_PACKAGE)/scripts && \ ( rm -f $(RM_SCRIPTS); chmod a-x mkcompile_h ) + find $(CURDIR)/debian/$(HEADERS_PACKAGE) -name ".gitignore" -exec rm {} \; install-libc-headers: dh_testdir diff --git a/kernel-bfs-2.6.28/debian/rx51power_defconfig b/kernel-bfs-2.6.28/debian/rx51power_defconfig index d3e4781..dce1caa 100644 --- a/kernel-bfs-2.6.28/debian/rx51power_defconfig +++ b/kernel-bfs-2.6.28/debian/rx51power_defconfig @@ -391,7 +391,7 @@ CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y CONFIG_XFRM=y -# CONFIG_XFRM_USER is not set +CONFIG_XFRM_USER=y # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set # CONFIG_XFRM_STATISTICS is not set @@ -404,7 +404,7 @@ CONFIG_IP_ADVANCED_ROUTER=y CONFIG_ASK_IP_FIB_HASH=y # CONFIG_IP_FIB_TRIE is not set CONFIG_IP_FIB_HASH=y -# CONFIG_IP_MULTIPLE_TABLES is not set +CONFIG_IP_MULTIPLE_TABLES=y # CONFIG_IP_ROUTE_MULTIPATH is not set # CONFIG_IP_ROUTE_VERBOSE is not set CONFIG_IP_PNP=y @@ -435,8 +435,8 @@ CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y # CONFIG_IPV6_ROUTE_INFO is not set # CONFIG_IPV6_OPTIMISTIC_DAD is not set -# CONFIG_INET6_AH is not set -# CONFIG_INET6_ESP is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_MIP6=m CONFIG_INET6_XFRM_TUNNEL=m @@ -507,7 +507,7 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m # CONFIG_NETFILTER_XT_MATCH_MARK is not set CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m # CONFIG_NETFILTER_XT_MATCH_OWNER is not set -# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=m # CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set # CONFIG_NETFILTER_XT_MATCH_QUOTA is not set # CONFIG_NETFILTER_XT_MATCH_RATEEST is not set @@ -678,6 +678,7 @@ CONFIG_BT_HIDP=m CONFIG_BT_HCIH4P=m # CONFIG_BT_HCIVHCI is not set # CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y CONFIG_WIRELESS=y CONFIG_CFG80211=y CONFIG_NL80211=y -- 1.7.9.5